【问题标题】:Receiving multiple incoming messages for a single send一次发送接收多条传入消息
【发布时间】:2015-02-17 18:56:36
【问题描述】:

我正在开发一个简单的 UDP 消息传递系统,并且大部分时间都在工作。该结构是有 1 台服务器,它简单地将消息广播到在特定端口上侦听的所有客户端(它仅用于未连接到 Internet 的 LAN 或 ad-hoc 网络,尽管我的测试 PC 目前已插入网络)。我的问题是,每次我发送消息时,客户端都会收到 2 个副本。目前我没有将目标 IP 设置为子网,所以这可能是问题所在:

(注意:我知道我违反了标准的客户端-服务器术语,因为我的“客户端”正在绑定一个特定的端口,但请耐心等待)。

所以这是我的服务器指定目标数据的方式:

   d_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);

   if(d_socket == -1)
   {
      printf("\nError in creating socket");
      return false;
   }

   //socket option set to 1 because we are setting the SO_BROADCAST setting to true
   //MSDN says to use int for boolean option types.
   int l_socket_option = 1;

   setsockopt(d_socket, 
              SOL_SOCKET, 
              SO_BROADCAST, 
              (char*)&l_socket_option, 
              sizeof(int));

   //Zero out the broadcast address member to initialize it
   memset(&d_broadcast_address,
          0, 
          sizeof(d_broadcast_address));

   //Specify that 
   d_broadcast_address.sin_family = AF_INET;
   d_broadcast_address.sin_port = htons(34444);
   d_broadcast_address.sin_addr.s_addr = INADDR_BROADCAST;

我的客户这样打开端口:

d_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);

   //Set port so that calls to recvfrom do not block. Instead recvfrom returns an error if no data is present now.
   u_long l_no_block_specifier = 1;
   int l_socket_control_result = ioctlsocket(d_socket,
                                             FIONBIO,
                                             &l_no_block_specifier);

   if(d_socket == -1)
   {
      printf("\nError in creating socket");
      return false;
   }

   //Zero out the broadcast address member to initialize it
   memset(&d_server_address,
          0, 
          sizeof(d_server_address));

   //Specify that 
   d_server_address.sin_family = AF_INET;
   d_server_address.sin_port = htons(34444);
   d_server_address.sin_addr.s_addr = INADDR_ANY;

   d_address_length = sizeof(d_server_address);

   //Bind socket and print an error if bind fails.
   if ( bind(d_socket, (SOCKADDR*)&d_server_address, sizeof(SOCKADDR_IN)) != 0 )
   {
      printf("\nError in binding socket");
   }

打开端口后,客户端会生成一个线程来重复读取端口。我编写了一个小型测试应用程序,它只发送一个整数,每个代表消息的序列。该程序的输出如下:

Sending message #0 at time = 4.0
Got message #0 at time = 4.0
Got message #0 at time = 25.0
Sending message #1 at time = 1004.0
Got message #1 at time = 1004.0
Got message #1 at time = 1047.0
Got message #2 at time = 2004.0
Sending message #2 at time = 2004.0
Got message #2 at time = 2064.0
Sending message #3 at time = 3005.0
Got message #3 at time = 3005.0
Got message #3 at time = 3086.0

我已经对其进行了彻底的测试,并且确信程序本身不会意外地为每条消息打印出 2 条通知(除了时间戳显示 2 条收据之间的迟到)。

为什么会这样?我猜这是因为我的测试 PC 已连接到 Internet,因此由于广播,消息通过 2 条不同的路径路由回我自己的 PC。

编辑:

我更改了客户端,使其使用自己的 IP 地址绑定广播端口,而不是指定 INADDR_ANY,这样就停止了重复收据。我还更新了服务器,使其仅在它所属的子网中广播,但我认为这不会对多个收据产生影响。

【问题讨论】:

  • 您没有显示您的实际发送或读取代码,但我猜想因为您发送到INADDR_BROADCAST (255.255.255.255) 而不是特定的子网广播地址,并且正在绑定接收器到INADDR_ANY (0.0.0.0) 而不是特定的 NIC,您可能会从接收器上的不同 NIC 接收每条消息的多个副本。您可以使用WSARecvMsg() 而不是recvfrom() 来确定哪个网卡实际接收每个数据包。
  • 是的,我没有粘贴发送/接收代码,因为那会很多。当我执行 ipconfig 时,我看到我有 2 个 IP 地址,1 个来自“以太网适配器本地连接”,另一个来自“无线 LAN 适配器无线网络连接”。所以我猜测额外的消息来自我的机器上有 2 个 IP 目标以便消息命中?

标签: sockets visual-c++ udp winsock


【解决方案1】:

我更改了客户端,使其使用自己的 IP 地址绑定广播端口,而不是指定 INADDR_ANY,这样就停止了重复收据。我还更新了服务器,使其仅在它所属的子网上广播,但我认为这不会对多个收据产生影响。 ——伊恩

【讨论】:

    猜你喜欢
    • 2018-04-12
    • 1970-01-01
    • 2012-06-05
    • 2020-02-26
    • 1970-01-01
    • 1970-01-01
    • 2018-03-31
    • 2023-03-31
    • 2019-11-08
    相关资源
    最近更新 更多