免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 18783 | 回复: 7
打印 上一主题 下一主题

[函数] 发一个随机获取空闲端口的函数 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-10-14 20:23 |只看该作者 |倒序浏览
随机获取一个系统的空闲端口,大家可能觉得不太常用
因为我们需要绑定一个随机端口的时候,直接把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;
}

        

论坛徽章:
0
2 [报告]
发表于 2007-10-14 20:33 |只看该作者
原帖由 Jass 于 2007-10-14 20:23 发表
随机获取一个系统的空闲端口,大家可能觉得不太常用
因为我们需要绑定一个随机端口的时候,直接把sockaddr_in.sin_port = 0或sockadd_in6.sin_port = 0就行了
我今天接触到一个应用,就出现了这种需要:
应用 ...

这样返回的端口不知道还能不能马上使用。
没试过

论坛徽章:
0
3 [报告]
发表于 2007-10-14 20:35 |只看该作者
原帖由 jaffaz 于 2007-10-14 20:33 发表

这样返回的端口不知道还能不能马上使用。
没试过



可以用循环,如果bind是EINVAL就再次调用获取一个新的端口
嗯 大家多多提意见 担心有隐患在里面

[ 本帖最后由 Jass 于 2007-10-14 20:38 编辑 ]

论坛徽章:
0
4 [报告]
发表于 2007-10-14 20:46 |只看该作者
原帖由 Jass 于 2007-10-14 20:35 发表



可以用循环,如果bind是EINVAL就再次调用获取一个新的端口
嗯 大家多多提意见 担心有隐患在里面

你的函数获得这个端口和接下来你使用(绑定)这个端口不是一个原子操作,多进程环境下有可能返回地址已经使用的错误

论坛徽章:
0
5 [报告]
发表于 2007-10-14 20:48 |只看该作者
既然你不关心端口号,为何不如你的get_free_port函数一样,sin_port=0后再用getsockname得到它?

论坛徽章:
0
6 [报告]
发表于 2007-10-14 20:54 |只看该作者
原帖由 jaffaz 于 2007-10-14 20:46 发表

你的函数获得这个端口和接下来你使用(绑定)这个端口不是一个原子操作,多进程环境下有可能返回地址已经使用的错误


这个好象不由这个函数来避免,只能通过判断bind失败的返回值是什么,决定要不要重新获得端口进行绑定

因为流程是这样,先定义一个addrinfo结构,然后调用getaddrinfo(char *node, char *service....struct addrinfo*result)给它初始化
然后bind再利用返回的addrinfo作为参数进行调用

看过的书里都是这样用的,不知道有什么其它的办法没有

或者可以自己封装一个Bind函数,在里面实现原子操作,呵呵

[ 本帖最后由 Jass 于 2007-10-14 21:01 编辑 ]

论坛徽章:
0
7 [报告]
发表于 2007-10-15 12:38 |只看该作者
原帖由 jaffaz 于 2007-10-14 20:48 发表
既然你不关心端口号,为何不如你的get_free_port函数一样,sin_port=0后再用getsockname得到它?


参见我的另一贴,及16楼的跟贴
http://bbs.chinaunix.net/thread-1002342-1-1.html

多谢你关心我这个问题,希望能继续给出宝贵的建议

[ 本帖最后由 Jass 于 2007-10-15 12:53 编辑 ]

论坛徽章:
0
8 [报告]
发表于 2011-11-15 11:57 |只看该作者
这个功能在网上还真不好找呀。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP