我如何获得免费套接字端口? C ++

时间:2022-12-15 15:05:38

I am writing a UDP test client/server and i want to get it through firewall. Supposedly all i need to do is have both sides send to the correct IP and server. Getting an IP is not a problem but how do i have the client pick a random free port and report it to the user? I eventually would want it to connect to a matchmaker server but right now i need a simple working prototype and i would like to cout the port number so my friend/tester can send me the # via IM so we can test.

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

How do i get the port number? sorry for the long desc. I notice people tell me not to do what i am asking when i dont give a desc :(

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

6 个解决方案

#1


To use the highly technical term, this is actually a pretty icky problem or even a pair of icky problems. Depending on the configuration of the firewall, it will usually allow responses from another endpoint on the IP endpoint as the request came from. So... if you friend receives the UDP datagram using something like the recvfrom() system call, the address parameter will receive the IP endpoint information to respond to. So the other end should be able to respond with a sendto() using the same addressing information. Something like:

要使用高技术术语,这实际上是一个非常棘手的问题,甚至是一对棘手的问题。根据防火墙的配置,它通常会在请求来自时允许来自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);

The peeraddr on the other side will be your external address or, more correctly, the IP address of your firewall and the port number that it chose to use. The port number that you specify in your code may be completely different than the port that your friend would have to send data to. Ultimately, it might not matter what port you choose to use since the firewall might be sending and receiving on an entirely different port - this is what Network Address Translation is all about. I would recommend reading RFC3235 for some tips on how to overcome that hurdle.

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

The best approach IMHO is to:

恕我直言的最佳方法是:

  1. Let the OS choose a port by either calling bind() with a zero port number or skipping the bind altogether
  2. 让操作系统通过调用具有零端口号的bind()或完全跳过绑定来选择端口

  3. Having the client receive the address information from the socket layer (e.g., the fifth and sixth arguments to recvfrom())
  4. 让客户端从套接字层接收地址信息(例如,recvfrom()的第五和第六个参数)

  5. The client sends response to the endpoint retrieved in the previous step
  6. 客户端将响应发送到上一步中检索到的端点

  7. Tweak the firewall configurations until the previous steps work
  8. 调整防火墙配置,直到前面的步骤工作

Of course, all of the magic is in the last step. If you can disable NAT or ensure that the firewall is never going to switch ports, then nailing down a port number and bind-ing to it will work as well. You might want to take a look at %WINDIR%\system32\drivers\etc\services (or /etc/services depending on your OS inclination) to get an idea of what port numbers are reserved or generally in use.

当然,所有的魔力都在最后一步。如果您可以禁用NAT或确保防火墙永远不会切换端口,那么固定端口号并绑定到它也可以。您可能需要查看%WINDIR%\ system32 \ drivers \ etc \ services(或/ etc / services,具体取决于您的操作系统倾向),以了解保留或通常使用的端口号。

#2


Generally speaking - you - as the developer - choose the port. You can set your application to read the port from a config file or user input - but no magic firewall is going to tell you what port to use...

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

#3


If I'm understanding your question correctly, I'm not sure there's a way to do what you want programatically (and even if there is, I don't think it's the right approach). I think you need to find a port that isn't in use on the server machine (and perhaps a different or the same port on the client machine, if communication is bi-directional) AND that port must be able to pass through your firewall. I assume since you say "getting an IP is not a problem", you've already configured your firewall to forward some or all ports to a specific computer inside the firewall? If so, the port you seek is one of the ones you forwarded. You can just pick an arbitrary one, as long as no other service is running on that port. Ports below 1024 are reserved, so you probably want to pick a higher number than that. You can use a simple portscanning tool such as nmap to see which services are running on your computer on which ports and pick a different one. Note that nmap can be fooled by firewalls and various bind rules when sockets are created.

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

#4


I think you're better off picking a fixed port rather than relying on the random port number chosen by the O/S.

我认为你最好选择固定端口,而不是依靠O / S选择的随机端口号。

If you use a random port you'd have to change your firewall settings each and every time you run the program.

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

#5


If you're using WINSOCK check this link: http://msdn.microsoft.com/en-us/library/aa280717(VS.60).aspx Basically you have 2 choices set the port to 0 and let the system assign you one or chose a random one try to open the socket if it doesn't work try another (be sure to steer clear of reserved ports)

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

#6


bind() the socket before you send your data. Specify port 0 to bind(), and the OS will pick an unused port for you. You can then use getsockname() to find out what port wsa chosen.

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

#1


To use the highly technical term, this is actually a pretty icky problem or even a pair of icky problems. Depending on the configuration of the firewall, it will usually allow responses from another endpoint on the IP endpoint as the request came from. So... if you friend receives the UDP datagram using something like the recvfrom() system call, the address parameter will receive the IP endpoint information to respond to. So the other end should be able to respond with a sendto() using the same addressing information. Something like:

要使用高技术术语,这实际上是一个非常棘手的问题,甚至是一对棘手的问题。根据防火墙的配置,它通常会在请求来自时允许来自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);

The peeraddr on the other side will be your external address or, more correctly, the IP address of your firewall and the port number that it chose to use. The port number that you specify in your code may be completely different than the port that your friend would have to send data to. Ultimately, it might not matter what port you choose to use since the firewall might be sending and receiving on an entirely different port - this is what Network Address Translation is all about. I would recommend reading RFC3235 for some tips on how to overcome that hurdle.

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

The best approach IMHO is to:

恕我直言的最佳方法是:

  1. Let the OS choose a port by either calling bind() with a zero port number or skipping the bind altogether
  2. 让操作系统通过调用具有零端口号的bind()或完全跳过绑定来选择端口

  3. Having the client receive the address information from the socket layer (e.g., the fifth and sixth arguments to recvfrom())
  4. 让客户端从套接字层接收地址信息(例如,recvfrom()的第五和第六个参数)

  5. The client sends response to the endpoint retrieved in the previous step
  6. 客户端将响应发送到上一步中检索到的端点

  7. Tweak the firewall configurations until the previous steps work
  8. 调整防火墙配置,直到前面的步骤工作

Of course, all of the magic is in the last step. If you can disable NAT or ensure that the firewall is never going to switch ports, then nailing down a port number and bind-ing to it will work as well. You might want to take a look at %WINDIR%\system32\drivers\etc\services (or /etc/services depending on your OS inclination) to get an idea of what port numbers are reserved or generally in use.

当然,所有的魔力都在最后一步。如果您可以禁用NAT或确保防火墙永远不会切换端口,那么固定端口号并绑定到它也可以。您可能需要查看%WINDIR%\ system32 \ drivers \ etc \ services(或/ etc / services,具体取决于您的操作系统倾向),以了解保留或通常使用的端口号。

#2


Generally speaking - you - as the developer - choose the port. You can set your application to read the port from a config file or user input - but no magic firewall is going to tell you what port to use...

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

#3


If I'm understanding your question correctly, I'm not sure there's a way to do what you want programatically (and even if there is, I don't think it's the right approach). I think you need to find a port that isn't in use on the server machine (and perhaps a different or the same port on the client machine, if communication is bi-directional) AND that port must be able to pass through your firewall. I assume since you say "getting an IP is not a problem", you've already configured your firewall to forward some or all ports to a specific computer inside the firewall? If so, the port you seek is one of the ones you forwarded. You can just pick an arbitrary one, as long as no other service is running on that port. Ports below 1024 are reserved, so you probably want to pick a higher number than that. You can use a simple portscanning tool such as nmap to see which services are running on your computer on which ports and pick a different one. Note that nmap can be fooled by firewalls and various bind rules when sockets are created.

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

#4


I think you're better off picking a fixed port rather than relying on the random port number chosen by the O/S.

我认为你最好选择固定端口,而不是依靠O / S选择的随机端口号。

If you use a random port you'd have to change your firewall settings each and every time you run the program.

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

#5


If you're using WINSOCK check this link: http://msdn.microsoft.com/en-us/library/aa280717(VS.60).aspx Basically you have 2 choices set the port to 0 and let the system assign you one or chose a random one try to open the socket if it doesn't work try another (be sure to steer clear of reserved ports)

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

#6


bind() the socket before you send your data. Specify port 0 to bind(), and the OS will pick an unused port for you. You can then use getsockname() to find out what port wsa chosen.

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