• socket报错:bind:address already in use


    写了一个tcp socket包含服务器和客户端,当用Ctrl + C后终止服务端后,再次启动时报错:

    bind:address already in use
    
    • 1

    就是说端口重复占用了,寻思着是Ctrl + C暴力停止,没有调用close关闭socket。

    close(server_sockfd);
    close(client_sockfd);
    
    • 1
    • 2

    加入上述函数后依然报这个错误,看来事情没有我想的那么简单。
    这个时候根据进程名和端口号来查进程号,发现都查不到,不由得虎躯一震,背部发凉。

    ps -ef | grep tcpServerDemo
    lsof -i:8888
    
    • 1
    • 2

    后来查资料发现即使进程终止,socket也会有一个TIME-WAIT状态,它大概持续2-4分钟,当然也可能更长,过了这个时间就会释放这个端口号。
    用这个命令可以看到处于TIME-WAIT状态的端口号:

    netstat -an | grep 8888
    
    • 1

    那么怎么才能立即启动而不是等待这个TIME-WAIT结束呢?

    	my_addr.sin_family=AF_INET; //设置为IP通信
    	my_addr.sin_addr.s_addr=INADDR_ANY;//服务器IP地址--允许连接到所有本地地址上
    	my_addr.sin_port=htons(1234); //服务器端口号
        //创建服务器端套接字--IPv4协议,面向连接通信,TCP协议
        if((server_sockfd=socket(PF_INET,SOCK_STREAM,0))<0)
        {
            cout<<"socket error";
            return ;
        }
        //使端口可以重复使用
        int iSockOptVal = 1;
        if (setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &iSockOptVal, sizeof(iSockOptVal)) == -1)
        {
            perror("setsockopt fail");
            close(server_sockfd);
            exit(EXIT_FAILURE);
        } 
        //套接字绑定在服务器的网络地址下
        if(bind(server_sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))<0)
        {
            cout<<"bind error";
    	perror("bind error:");
            return ;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    其实就是添加一个setsockopt()函数,SO_REUSEADDR和iSockOptVal都是设置可重复使用的参数,其中iSockOptVal若为0则表示不能重复使用。
    这个时候其实还是有TIME-WAIT,但是不影响我们重复使用同一个端口。

    下面来了解一下TIME-WAIT:
    这个有存在的必要吗,当然!存在就有它的合理性。
    1.用来保证被动关闭的另一端也能正确关闭。
    2.防止新启动的端口接收到旧的数据包。
    存在的原因具体参考:TIME-WAIT原因

    那么客户端和服务端谁先启动呢?
    最好服务端,这样客户端发的每一条数据才能有反馈。
    谁先关闭呢?
    客户端关闭则服务端会收到服务端关闭的通知;但服务端关闭,则客户端需要发送一次请求才能得知服务端已经关闭。
    因此先关闭客户端比较好,还有一个原因,这个服务端可能对应多个客户端,当然不能随便因为一个客户端不用了就关闭。

    参考:客户端服务端关闭时函数返回值

  • 相关阅读:
    react轮播图如何实现
    最短编辑距离
    【python基础】input函数
    使用福禄克CFP光纤测试仪进行Tier 1和Tier 2光纤测试
    io_uring 之 liburing 的简单使用
    数据中台可视化:赋能企业数据应用的关键一步
    hadoop、hive、DBeaver的环境搭建及使用
    好的摄影师都会iPhone 8和iOS 11的这三项功能
    uniapp实战项目 (仿知识星球App) - - tabBar配置
    elk日志收集系统
  • 原文地址:https://blog.csdn.net/weixin_43466192/article/details/126350235