我正在编写UDP测试客户端/服务器,我希望通过防火墙。据说我需要做的就是让双方都发送到正确的IP和服务器。获取IP不是问题,但我如何让客户端选择随机空闲端口并将其报告给用户?我最终希望它连接到一个媒人服务器,但是现在我需要一个简单的工作原型,我想知道端口号,所以我的朋友/测试人员可以通过即时消息发送给我#所以我们可以测试。

我如何获得端口号? 抱歉,长期的desc。我注意到人们告诉我不要做什么,当我不给出desc时我会问:(

有帮助吗?

解决方案

使用高技术术语,这实际上是一个非常棘手的问题,甚至是一对棘手的问题。根据防火墙的配置,它通常会在请求来自时允许来自IP端点上另一个端点的响应。所以...如果你的朋友使用类似 recvfrom()系统调用的东西收到UDP数据报,地址参数将收到要响应的IP端点信息。所以另一端应该能够使用相同的寻址信息用 sendto()进行响应。类似的东西:

/* initiator */
struct sockaddr_in hisaddr;
memset(&hisaddr, 0, sizeof(hisaddr));
hisaddr.sin_addr.s_addr = htonl(target_ip);
hisaddr.sin_port = htons(target_port);
sendto(sd, msg_ptr, msg_sz, 0, (struct sockaddr*)&hisaddr, sizeof(hisaddr));

/* receiver */
struct sockaddr_in peeraddr;
socklen_t peer_sz = sizeof(peeraddr);
recvfrom(sd, buf_ptr, buf_sz, 0, (struct sockaddr*)&peeraddr, &peer_sz);
/* build response */
sendto(sd, msg_ptr, msg_sz, 0, (struct sockaddr*)&peeraddr, peer_sz);

另一方面的 peeraddr 将是您的外部地址,或者更确切地说,是防火墙的IP地址和它选择使用的端口号。您在代码中指定的端口号可能与您的朋友必须向其发送数据的端口完全不同。最终,由于防火墙可能在完全不同的端口上发送和接收,因此您选择使用哪个端口可能无关紧要 - 这就是网络地址转换就是这样。我建议阅读 RFC3235 ,了解如何克服这一障碍的一些提示。

恕我直言的最佳方法是:

  1. 让操作系统选择一个端口,方法是调用 bind() ,端口号为零或完全跳过绑定
  2. 让客户端从套接字层接收地址信息(例如, <代码> recvfrom的()
  3. 客户端向上一步检索到的端点发送响应
  4. 调整防火墙配置,直到前面的步骤正常工作
  5. 当然,所有的魔力都在最后一步。如果您可以禁用NAT或确保防火墙永远不会切换端口,那么确定端口号和 bind -ing也可以正常工作。您可能需要查看%WINDIR%\ system32 \ drivers \ etc \ services (或 / etc / services ,具体取决于您的操作系统倾向)以了解保留或通常使用的端口号。

其他提示

一般而言 - 您 - 作为开发人员 - 选择端口。您可以将应用程序设置为从配置文件或用户输入读取端口 - 但是没有魔术防火墙会告诉您要使用的端口...

如果我正确地理解你的问题,我不确定是否有办法以编程方式做你想做的事(即使有,我认为这不是正确的方法)。我认为您需要在服务器计算机上找到一个未使用的端口(如果通信是双向的,可能是客户端计算机上的不同或相同端口)并且该端口必须能够通过您的防火墙。我假设您说“获取IP不是问题”,您已经将防火墙配置为将部分或全部端口转发到防火墙内的特定计算机?如果是这样,您寻找的端口就是您转发的端口之一。只要该端口上没有运行其他服务,您就可以选择任意一个。低于1024的端口是保留的,因此您可能希望选择比此更高的数字。您可以使用简单的端口扫描工具(例如 nmap )查看您的计算机上正在哪些服务上运行哪些端口并选择不同的端口一。请注意,创建套接字时, nmap 可能被防火墙和各种 bind 规则所欺骗。

我认为你最好选择固定端口,而不是依赖于操作系统选择的随机端口号。

如果使用随机端口,则每次运行程序时都必须更改防火墙设置。

如果您正在使用WINSOCK,请检查以下链接: http://msdn.microsoft.com/en-us /library/aa280717(VS.60).aspx 基本上你有2个选择将端口设置为0并让系统为你分配一个或者选择一个随机尝试打开套接字如果它不起作用尝试另一个(确保避开保留端口)

在发送数据之前

绑定()套接字。将端口0指定为bind(),操作系统将为您选择一个未使用的端口。然后,您可以使用getsockname()来找出所选择的端口。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top