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
,会发生什么情况?他们会为传入的连接而争吵吗#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