使用两台主机之间的不同端口进行UDP套接字通信

时间:2014-07-14 15:48:15

标签: sockets udp bind

我有一个设备可以侦听端口IN_PORT上的UDP数据包,并在端口OUT_PORT上回显消息。我可以使用Packet Sender等测试软件与它进行通信。

我必须编写一个C ++库(目前是Win32)来与设备通信。我做了几次测试,但我还是无法沟通。我的猜测是使用这个工作流程:

  1. 创建套接字
  2. 使用设备地址,AF_INET系列和侦听端口(OUT_PORT)填充sockaddr_in结构
  3. 绑定套接字
  4. 使用IN_PORT更改sockaddr_in.sin_port并发送数据包(使用sendto)
  5. 等待答案(使用recvfrom)
  6. 从4开始重复
  7. 如果我使用Packet Sender实用程序在本地工作(设备地址= 127.0.0.1)来模拟设备,则此方法有效。我无法使用相同的工作流连接到远程地址,即使在同一子网中(例如我的PC地址:192.168.1.2,远程PC地址192.168.1.5),因为我收到WSAEADDRNOTAVAIL错误。

    我已经测试了几个不同的工作流程,并在这里和那里阅读了关于这个主题的几个讨论,但没有一个工作,非常好。

    有人可以给我一些关于这个问题的提示。

    谢谢!

    MIX

2 个答案:

答案 0 :(得分:1)

您的工作流程略有错误。它应该更像是这样:

  1. 创建套接字
  2. 使用与设备通信的本地网络适配器的地址,AF_INET系列和listenig端口(OUT_PORT)填充sockaddr_in结构
  3. 绑定套接字
  4. sockaddr.sin_addr更改为设备地址,将sockaddr_in.sin_port更改为IN_PORT,并发送数据包(使用sendto)
  5. 等待答案(使用recvfrom)
  6. 从4开始重复

答案 1 :(得分:0)

我在 Remy Lebeau 提示后更改了我的代码。它现在有效。如果有人想看看并发现一些弱点,或提出改进建议,我会很高兴(一个“正常工作”的代码永远不够;它也必须“闪耀”!)。注释标记代码的上一个(错误)版本。

#pragma comment (lib, "Ws2_32.lib")

#include <winsock2.h>
#include <stdlib.h>
#include <stdio.h>
#include <STRING>

#define IN_PORT 18
#define OUT_PORT 17
#define LOCAL_IP "10.0.10.108"
#define DEVICE_IP "10.0.10.104"

#define DEFAULT_BUFLEN  1024

int main(int argc, char *argv[])
{
  WSADATA wsaData;
  SOCKET sck;
  struct sockaddr_in sckAddrInfo;
  bool terminate;
  char dataBuffer[DEFAULT_BUFLEN];
  int rcvDataLength;
  int sckAddrInfoLength;

  WSAStartup(MAKEWORD(2,2), &wsaData);
  sck = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

  memset((&sckAddrInfo), 0, sizeof(sckAddrInfo));
  sckAddrInfo.sin_family = AF_INET;
  sckAddrInfo.sin_port = htons(IN_PORT);
  //sckAddrInfo.sin_addr.s_addr = inet_addr(DEVICE_IP);  // WRONG! Must bind local address
  sckAddrInfo.sin_addr.s_addr = inet_addr(LOCAL_IP);
  bind(sck, (struct sockaddr*)(&sckAddrInfo), sizeof(sckAddrInfo));

  terminate = false;
  sckAddrInfoLength = sizeof(sckAddrInfo);
  while(!terminate)
  {
    printf("Write echo request: ");
    gets(dataBuffer);

    sckAddrInfo.sin_addr.s_addr = inet_addr(DEVICE_IP); // Must set device address, too, not just output port
    sckAddrInfo.sin_port = htons(OUT_PORT);
    sendto(sck, dataBuffer, strlen(dataBuffer), 0, (struct sockaddr*)(&sckAddrInfo), sizeof(sckAddrInfo));

    memset(dataBuffer, '\0', DEFAULT_BUFLEN);

    rcvDataLength = recvfrom(sck, dataBuffer, DEFAULT_BUFLEN, 0, (struct sockaddr*)(&sckAddrInfo), &sckAddrInfoLength);

    printf("Device answer: %s\n", dataBuffer);

    if(strcmp(dataBuffer, "quit") == 0)
      terminate = true;
  }

  closesocket(sck);
  WSACleanup();

  return 0;
}