Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 选择已在使用的本地源端口_C_Sockets_Tcp_Network Programming_Posix - Fatal编程技术网

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

C 选择已在使用的本地源端口,c,sockets,tcp,network-programming,posix,C,Sockets,Tcp,Network Programming,Posix,我希望使用特定的本地端口连接到远程服务器,而不是内核随机分配的端口。我可以通过调用bind()绑定到本地端口,然后再调用connect()到远程服务器 我的问题是,如果我要使用的本地端口已经被另一个应用程序使用,会发生什么情况?只要目标端口或远程端口不同,我无论如何都可以使用它(就像服务器可以accept()端口80上的多个连接一样)。但是在这种情况下,我的bind调用不应该失败吗?如果是,我如何设置套接字以使用另一个应用程序已经使用的本地端口 我之所以要这样做,是因为我正在尝试编写一个本地代理

我希望使用特定的本地端口连接到远程服务器,而不是内核随机分配的端口。我可以通过调用
bind()
绑定到本地端口,然后再调用
connect()
到远程服务器

我的问题是,如果我要使用的本地端口已经被另一个应用程序使用,会发生什么情况?只要目标端口或远程端口不同,我无论如何都可以使用它(就像服务器可以
accept()
端口80上的多个连接一样)。但是在这种情况下,我的
bind
调用不应该失败吗?如果是,我如何设置套接字以使用另一个应用程序已经使用的本地端口


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

bind
只知道一个端点

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


另一方面,
accept
知道两个对等方。

您可以提出一个论点,认为您无论如何都应该能够使用它,但是TCP实现不允许您使用它,除非两个绑定不同。例如,您可能能够绑定到具有不同IP地址的同一端口

允许重叠绑定存在两个问题:

  • 如果两个应用程序都调用
    accept
    ,会发生什么情况?他们会为传入的连接而争吵吗

  • 如果两个应用程序都试图建立到同一IP和端口的出站连接,会发生什么情况?如何区分这两种联系

  • 现在这些问题都可以解决了。但我不知道有哪种实现会让人烦恼。理由是这些应用程序必须合作,否则会得到令人惊讶的结果。如果他们合作,他们可以共享绑定的套接字

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

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

    如果套接字未设置SO\U 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;
    }
    
    使用SO_REUSEADDR,您可以连接到不同的远程服务器:

    $ ./client google.com
    $ ./client stackoverflow.com
    
    但是,连接将不允许您打开两个具有相同源和目标的套接字:

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

    对于“我的
    bind
    调用是否会失败”的问题,您应该能够自己测试它,因为您计划无论如何都要编写这个程序。我真的很想知道我可以依赖什么行为以及背后的原因,我不是专家,也不相信任何一个测试用例:)我也不是网络编程专家。我提出这个建议是因为我会这样做来确定答案。有点通用,但它可能会帮助您找到正确的方向。如果两个套接字都已连接,则目标可以由对等IP和端口确定。如果套接字已绑定但未连接,则不应接收任何数据包。谢谢。为什么内核在绑定时抛出错误,而不是在案例1中尝试侦听时以及在案例2中尝试连接时抛出错误?。条件可以是“您无法在该端口/IP上侦听,因为其他人已在侦听”和“您无法连接到该端口IP,因为其他人已从同一端口连接”,让
    bind
    始终成功。@然后,如果一个进程
    bind
    s和另一个进程
    connect
    s从IP接收到传入连接,而另一个进程试图
    连接到该端口,会发生什么情况?如果他们在合作,他们不需要两者都绑定。如果他们不是,那么他们就不能同时绑定。解决所有这些问题要麻烦得多,而且过程无论如何都必须配合。如果他们在合作,他们不需要同时绑定
    ——他们可以共享绑定的套接字。我想如果其他人正在监听,你不能让连接,反之亦然,因为绑定并不一定意味着监听。我明白你的意思,尽管它很混乱。如果我不控制的另一个应用程序正在使用一个端口,你是说我无法将该端口与另一个目标IP一起使用吗?我已经对这个问题做了一些澄清,说明了我想做什么。@Andrew是的,除了以特定于平台的方式侵入性地“窃取”应用程序中的套接字之外,没有其他方法了(例如,在Linux上,您可以从
    /proc//fd/
    中获取它)。应用程序不知道如何处理所有可能出现的问题,也不知道如何与您协调以避免这些问题。
    $ ./client google.com
    $ ./client google.com
    connect: Cannot assign requested address