TCP/IP UDP广播无法发送或接收

news/2024/5/17 15:14:03 标签: tcp/ip, udp, 广播, 多播, Socket, 局域网, tcp

TCP/IP UDP广播无法发送或者接收数据

在看《TCP/IP 网络编程》这本书的时候,看到广播那一节,跟着书上写代码,怎么写都不行,广播就是没法发送/接收,发送端一直在发送数据,接收端就是没有反应。

对了好几遍源码,没有问题。实在是愁人。

最后查了很多资料,确定是网卡的问题。

现在的计算机都是多网卡,至少是有线+无线网卡,如果安装了虚拟机的话,还会有虚拟网卡。

广播地址无法区分网卡,只能按照默认网卡优先级发送,这就导致我们的数据没有走那个我们需要的网卡发送出去。进而导致收不到数据。

解决办法

  1. 禁用一些网卡,将用不到的网卡全部禁用掉
  2. 在代码里添加绑定IP地址的逻辑,绑定到具体的网卡IP

我是用的是第2种方式,比较方便灵活。

发送端Linux源码:

#include <arpa/inet.h>
#include <asm-generic/socket.h>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <iostream>
#include <iterator>
#include <linux/in.h>
#include <sys/endian.h>
#include <sys/socket.h>
#include <unistd.h>

#ifndef FILEPATH
#define FILEPATH "../news.txt"
#endif

constexpr int BUF_SIZE = 30;

int main(int argc, char* argv[])
{
    if (argc != 4) {
        std::cout << "Usage: " << argv[0] << "<Self IP> <Boardcast IP> <PORT>" << std::endl;
        return 0;
    }

    int send_socket = socket(PF_INET, SOCK_DGRAM, 0);

    // 绑定到具体的网卡IP
    sockaddr_in self_adr;
    std::memset(&self_adr, 0, sizeof(self_adr));
    self_adr.sin_family = AF_INET;
    self_adr.sin_addr.s_addr = inet_addr(argv[1]);
    self_adr.sin_port = 0; // 随机分配一个端口
    int res = bind(send_socket, (sockaddr*)&self_adr, sizeof(self_adr));
    if (res == -1) {
        std::cout << "bind error";
    }

    sockaddr_in broad_adr;
    std::memset(&broad_adr, 0, sizeof(broad_adr));
    broad_adr.sin_family = AF_INET;
    broad_adr.sin_addr.s_addr = inet_addr(argv[2]);
    broad_adr.sin_port = htons(std::atoi(argv[3]));

    int so_brd = 1;
    int rtn = setsockopt(send_socket, SOL_SOCKET, SO_BROADCAST, &so_brd, sizeof(so_brd));
    if (rtn == -1) {
        std::cout << "setsockopt error" << std::endl;
        return 0;
    }

    std::ifstream fi { FILEPATH };
    while (!fi.eof()) {
        std::string msg;
        fi >> msg;
        int s = sendto(send_socket, msg.c_str(), msg.size(), 0, (sockaddr*)&broad_adr, sizeof(broad_adr));
        std::cout << s << ":" << msg << std::endl;
        sleep(2);
    }

    close(send_socket);

    return 0;
}


接收端Linux源码:

#include <arpa/inet.h>
#include <cstring>
#include <iostream>
#include <linux/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

constexpr int BUF_SIZE = 30;

int main(int argc, char* argv[])
{
    if (argc != 2) {
        std::cout << "Usage: " << argv[0] << " <PORT>" << std::endl;
        return 0;
    }

    int recv_sock = socket(PF_INET, SOCK_DGRAM, 0);

    sockaddr_in adr;
    std::memset(&adr, 0, sizeof(adr));
    adr.sin_family = AF_INET;
    adr.sin_addr.s_addr = htonl(INADDR_ANY);
    int port = std::atoi(argv[1]);
    adr.sin_port = htons(port);
    std::cout << "PORT: " << port << std::endl;

    int rtn = bind(recv_sock, (sockaddr*)&adr, sizeof(adr));
    if (rtn == -1) {
        std::cout << "bind error" << std::endl;
        return 0;
    }

    char buf[BUF_SIZE] = { 0 };
    while (true) {
        sockaddr_in src_adr;
        socklen_t sl = 0;
        int l = recvfrom(recv_sock, buf, BUF_SIZE - 1, 0, (sockaddr*)&src_adr, &sl);
        std::string srcIp = inet_ntoa(src_adr.sin_addr);
        std::cout << srcIp << " - ";
        if (l < 0) {
            break;
        }
        buf[l] = 0;
        std::cout << buf;
    }

    close(recv_sock);

    return 0;
}


接收端Win源码:

#include <WS2tcpip.h>
#include <WinSock2.h>
#include <cstdlib>
#include <cstring>
#include <iostream>

constexpr int BUF_SIZE = 30;

int main(int argc, char* argv[])
{
    if (argc != 2) {
        std::cout << "Usage: " << argv[0] << " <PORT>" << std::endl;
        return 0;
    }

    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        std::cout << "WSA error" << std::endl;
        return 0;
    }

    SOCKET recvSock = socket(PF_INET, SOCK_DGRAM, 0);
    SOCKADDR_IN adr;
    std::memset(&adr, 0, sizeof(adr));
    adr.sin_family = AF_INET;
    adr.sin_addr.s_addr = htonl(INADDR_ANY);
    int port = std::atoi(argv[1]);
    adr.sin_port = htons(port);

    int rtn = bind(recvSock, (SOCKADDR*)&adr, sizeof(adr));
    if (rtn == SOCKET_ERROR) {
        std::cout << "bind error" << std::endl;
        return 0;
    }

    std::cout << "服务已启动:" << port << std::endl;

    char buf[BUF_SIZE] = { 0 };
    while (true) {
        int strLen = recvfrom(recvSock, buf, BUF_SIZE - 1, 0, nullptr, 0);
        if (strLen < 0) {
            break;
        }
        buf[strLen] = 0;
        std::cout << buf << std::endl;
    }

    closesocket(recvSock);
    WSACleanup();

    return 0;
}


http://www.niftyadmin.cn/n/5012631.html

相关文章

全球市场争夺战:如何提升品牌在海外市场的竞争力?

随着全球化的不断发展&#xff0c;越来越多的企业将目光投向了海外市场&#xff0c;希望能够在国际舞台上获得更大的发展机会。然而&#xff0c;海外市场的竞争激烈&#xff0c;如何有效地提升品牌在海外市场的竞争力成为了一个关键的问题。本文Nox聚星将和大家从多个方面探讨&…

网络原理(一)网络基础,包括IP ,网络相关的定义

网络基础 以下图片是书上的网图。 什么是IP地址&#xff1f; IP地址&#xff08;Internet Protocol Address&#xff09;是指互联网协议地址&#xff0c;又译为网际协议地址。P地址是IP协议提供的一种统一的地址格式&#xff0c;它为互联网上的每一个网络和每一台主机分配一…

深入剖析HTTP和HTTPS代理在爬虫中的应用价值

在当今信息时代&#xff0c;数据是无处不在且极其宝贵的资源。对于从互联网上获取大量结构化或非结构化数据的需求而言&#xff0c;网络爬虫成为一种强有力的工具。然而&#xff0c;在实际操作过程中&#xff0c;我们常常会面临许多挑战和限制。   其中一个主要问题就是目标网…

Spring Cloud zuul与CloseableHttpClient连接池,TLS证书认证

前言 最近做项目&#xff0c;需要一个代理逻辑&#xff0c;实际上这种代理NGINX最好&#xff0c;但是有些额外功能的开发&#xff0c;NGINX就需要额外能力支持&#xff0c;比如lua脚本&#xff0c;常见的做法有kong&#xff0c;apisix等&#xff0c;据说apisix的性能较强&…

6种方法将python脚本打包成exe应用

文章目录 1、使用pyinstaller2、使用cx_Freeze3、使用py2exe4、使用py2app5、使用Nuitka6、使用Nuitkapyinstaller Python代码需要在Python解释器中运行&#xff0c;这对于一些用户来说可能不太方便。因此&#xff0c;将Python代码打包成可执行文件&#xff08;exe&#xff09;…

Python爬虫:Selenium的介绍及简单示例

Selenium是一个用于自动化Web应用程序测试的开源工具。它允许开发人员模拟用户在浏览器中的交互行为&#xff0c;以便自动执行各种测试任务&#xff0c;包括功能测试、性能测试和回归测试等。Selenium最初是为Web应用程序测试而创建的&#xff0c;但它也可用于Web数据抓取和其他…

Leetcode 567 Permutation in String (滑动窗口经典题)

Permutation in String Medium Given two strings s1 and s2, return true if s2 contains a permutation of s1, or false otherwise. In other words, return true if one of s1’s permutations is the substring of s2. Example 1: Input: s1 “ab”, s2 “eidbaooo” …

内网穿透实现Windows远程桌面访问Ubuntu,简单高效的远程桌面解决方案

文章目录 前言1. ubuntu安装XRDP2.局域网测试连接3.安装cpolar内网穿透4.cpolar公网地址测试访问5.固定域名公网地址 前言 XRDP是一种开源工具&#xff0c;它允许用户通过Windows RDP访问Linux远程桌面。 除了Windows RDP外&#xff0c;xrdp工具还接受来自其他RDP客户端(如Fre…