选择已在使用的本地源端口

时间:2014-05-14 05:20:32

标签: c sockets tcp network-programming posix

我想使用特定的本地端口连接到远程服务器,而不是内核随机分配的端口。我可以通过在调用bind()到远程服务器之前调用connect()绑定到本地端口来执行此操作。

我的问题是,如果我想使用的本地端口已被其他应用程序使用,会发生什么?无论如何,如果目标或远程端口不同,我应该能够使用它(与服务器在端口80上accept()多个连接的方式相同)。但是在这种情况下我的bind调用不应该失败,如果是这样,我怎样才能设置套接字以使用另一个应用程序已经在使用的本地端口?

我想这样做的原因是我正在尝试编写一个连接到检查源端口的服务器应用程序的本地代理。如果源端口错误,服务器将不允许连接。客户端应用程序连接到我的代理,我希望我的代理使用相同的端口连接到服务器 - 但如果代理在同一台机器上它将无法工作,因为该端口已被应用程序连接使用到我的代理人。

3 个答案:

答案 0 :(得分:2)

你可以提出一个论据,你应该能够使用它,但TCP实现不会让你,除非两个绑定不同。例如,您可能能够使用不同的IP地址绑定到同一端口。

允许重叠绑定有两个问题:

  1. 如果两个应用程序都调用accept会怎样?他们是否为传入的连接而战?

  2. 如果两个应用程序都尝试建立到同一IP和端口的出站连接,会发生什么?如何区分这两个连接?

  3. 现在这些问题可以解决了。但我不知道任何困扰的实施。争论的焦点是应用程序必须合作,否则会得到令人惊讶的结果。如果他们正在合作,他们可以共享绑定的套接字。

    所以答案是:如果您没有与拥有该端口的其他应用程序合作,那么您无权共享它。如果您正在与其他应用程序合作,请让它使用您的平台支持的方法为您提供其套接字的副本。

答案 1 :(得分:1)

>但在这种情况下,我的绑定调用不应该失败,

如果套接字没有设置SO_REUSEADDR选项,则为是。

>如果是这样,我如何设置套接字以使用其他应用程序已在使用的本地端口?

您的应用程序和另一个应用程序都必须在套接字上设置SO_REUSEADDR选项,该套接字要绑定到本地端口。

下面的代码从端口1111:

连接到HTTP服务器,以命令行参数的形式给出
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <netdb.h>

#define CLIENT_PORT 1111
#define SERVER_PORT 80

int main(int argc, char *argv[]) {

  struct sockaddr_in client_name, server_name;
  struct hostent *server_info;

  if (argc != 2)
    return printf("Exactly one argument is required: host to connect\n"), 1;

  int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
  if (sock_fd < 0)
    return perror("socket"), 1;

  /* Without the next 4 lines, bind refuses to use the same port */
  int reuseaddr = 1;
  if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
                 sizeof(reuseaddr)) < 0)
    return perror("setsockopt"), 1;

  client_name.sin_family = AF_INET;
  client_name.sin_port = htons(CLIENT_PORT);
  client_name.sin_addr.s_addr = htonl(INADDR_ANY);

  if (bind(sock_fd, (struct sockaddr *) &client_name, 
           sizeof(struct sockaddr_in)) < 0)
    return perror("bind"), 1;

  server_name.sin_family = AF_INET;
  server_name.sin_port = htons(SERVER_PORT);
  if ((server_info = gethostbyname(argv[1])) == NULL)
    return printf("Unknown host: %s\n", argv[1]), 1;

  server_name.sin_addr = *(struct in_addr *) server_info->h_addr;

  if (connect(sock_fd, (struct sockaddr *) &server_name, 
              sizeof(server_name)) < 0)
    return perror("connect"), 1;

  return 0;
}

&GT;如果我想使用的本地端口已被其他应用程序使用,会发生什么?

如果没有 SO_REUSEADDR (尝试注释setsockopt周围的4行),绑定会失败:

$ ./client google.com
$ ./client stackoverflow.com
bind: Address already in use

使用SO_REUSEADDR,您可以连接到不同的远程服务器:

$ ./client google.com
$ ./client stackoverflow.com

连接将不允许您打开两个具有相同来源目的地的套接字:

$ ./client google.com
$ ./client google.com
connect: Cannot assign requested address

答案 2 :(得分:-1)

bind只知道一个端点。

假设两个套接字绑定到同一个端口。传入的数据包应该路由到哪一个?

另一方面,

accept知道两个同行。