- 论坛徽章:
- 0
|
随机获取一个系统的空闲端口,大家可能觉得不太常用
因为我们需要绑定一个随机端口的时候,直接把sockaddr_in.sin_port = 0或sockadd_in6.sin_port = 0就行了
我今天接触到一个应用,就出现了这种需要:
应用场景是,编写ipv4、ipv6兼容的服务器程序,其中用到了类似ftp服务器的pasv模式
即服务器绑定一个随机的端口,把这个端口通过另外的连接告诉客户端,然后在此端口上等待连接到来
既然编写ipv?兼容的程序,根据unp的建议(另一本windows下的网络编程的经典名著《windows网络编程》也是如此说)
当然应该使用新的ipv?兼容的地址结构(addrinfo)与地址解析函数(getaddrinfo()、getnameinfo())
可以使程序员摆脱直接去操作sockaddr_in/sockaddr_in6结构的工作(其它好处我也说不上来了)
而在使用getaddrinfo(char *node, char *service....)的时候,问题就出来了
node 和 service不能同时为空,因此似乎不能通过getaddrinfo()直接地获取一个随机的空闲端口,而必须指定端口
因此这个函数的功能就是获取一个随机的空闲端口,然后作为参数,传给getaddrinfo函数
在这个函数里面肯定是不得不和sockaddr_in/sockaddr_in6打交道的,挺麻烦,但是提供这个函数的目的就在于
上层的程序员可以直接调用这个函数,给他们避免了这个麻烦
我基本是个菜鸟,经常上来问一些比较入门级别的问题,感谢大家的指点。
第一次发代码在上面,请大家拍吧
int get_free_port()
{
int port = 0;
int fd = -1;
socklen_t = 0;
port = -1;
#ifndef AF_IPV6
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(0);
sin.sin_addr.s_addr = htonl(INADDR_ANY);
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(fd < 0){
printf("socket() error:%s\n", strerror(errno));
return -1;
}
if(bind(fd, (struct sockaddr *)&sin, sizeof(sin)) != 0)
{
printf("bind() error:%s\n", strerror(errno));
close(fd);
return -1;
}
len = sizeof(sin);
if(getsockname(fd, (struct sockaddr *)&sin, &len) != 0)
{
printf("getsockname() error:%s\n", strerror(errno));
close(fd);
return -1;
}
port = sin.sin_port;
if(fd != -1)
close(fd);
#else
struct sockaddr_in6 sin6;
memset(&sin6, 0, sizeof(sin6));
sin.sin_family = AF_INET6;
sin.sin_port = htons(0);
sin6.sin_addr.s_addr = htonl(IN6ADDR_ANY);
fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if(fd < 0){
printf("socket() error:%s\n", strerror(errno));
return -1;
}
if(bind(fd, (struct sockaddr *)&sin6, sizeof(sin6)) != 0)
{
printf("bind() error:%s\n", strerror(errno));
close(fd);
return -1;
}
len = sizeof(sin6);
if(getsockname(fd, (struct sockaddr *)&sin6, &len) != 0)
{
printf("getsockname() error:%s\n", strerror(errno));
close(fd);
return -1;
}
port = sin6.sin6_port;
if(fd != -1)
close(fd);
#endif
return port;
}
|
|
|