我正在编写UDP测试客户端/服务器,我希望通过防火墙。据说我需要做的就是让双方都发送到正确的IP和服务器。获取IP不是问题,但我如何让客户端选择随机空闲端口并将其报告给用户?我最终希望它连接到一个媒人服务器,但是现在我需要一个简单的工作原型,我想知道端口号,所以我的朋友/测试人员可以通过即时通讯发送给我#所以我们可以测试。
我如何获得端口号? 抱歉,长期的desc。我注意到人们告诉我不要做什么,当我不给出desc时我会问:(
答案 0 :(得分:5)
要使用高技术术语,这实际上是一个非常棘手的问题,甚至是一对棘手的问题。根据防火墙的配置,它通常会在请求来自时允许来自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地址以及它选择使用的端口号。您在代码中指定的端口号可能与您的朋友必须向其发送数据的端口完全不同。最终,您选择使用哪个端口并不重要,因为防火墙可能在完全不同的端口上发送和接收 - 这就是Network Address Translation的全部内容。我建议阅读RFC3235以获取有关如何克服这一障碍的一些提示。
恕我直言的最佳方法是:
bind()
使用零端口号或完全跳过绑定来选择端口recvfrom()
的第五和第六个参数)当然,所有的魔力都在最后一步。如果您可以禁用NAT或确保防火墙永远不会切换端口,那么确定端口号并bind
- 也可以正常工作。您可能需要查看%WINDIR%\system32\drivers\etc\services
(或/etc/services
,具体取决于您的操作系统倾向),以了解保留或正在使用的端口号。
答案 1 :(得分:0)
一般而言 - 您 - 作为开发人员 - 选择端口。您可以将应用程序设置为从配置文件或用户输入读取端口 - 但是没有魔术防火墙会告诉您要使用的端口...
答案 2 :(得分:0)
如果我正确理解你的问题,我不确定是否有办法以编程方式做你想做的事(即使有,我认为这不是正确的方法)。我认为您需要在服务器计算机上找到一个未使用的端口(如果通信是双向的,可能是客户端计算机上的不同或相同端口)并且该端口必须能够通过您的防火墙。我假设你说“获取IP不是问题”,你已经配置防火墙将部分或全部端口转发到防火墙内的特定计算机?如果是这样,您寻找的端口就是您转发的端口之一。只要该端口上没有运行其他服务,您就可以选择任意一个。低于1024的端口是保留的,因此您可能希望选择比此更高的数字。您可以使用简单的端口扫描工具(例如nmap)查看计算机上正在哪些服务上运行哪些端口并选择其他端口。请注意,创建套接字时,nmap
可能会受到防火墙和各种bind
规则的欺骗。
答案 3 :(得分:0)
我认为你最好选择固定端口,而不是依赖于操作系统选择的随机端口号。
如果使用随机端口,则每次运行程序时都必须更改防火墙设置。
答案 4 :(得分:0)
如果您正在使用WINSOCK,请检查以下链接: http://msdn.microsoft.com/en-us/library/aa280717(VS.60).aspx 基本上你有2个选择将端口设置为0并让系统为你分配一个或者选择一个随机尝试打开套接字如果它不起作用尝试另一个(确保避开保留端口)
答案 5 :(得分:0)
绑定()套接字。将端口0指定为bind(),操作系统将为您选择一个未使用的端口。然后,您可以使用getsockname()来找出所选择的端口。