socket报错:bind:address already in use

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

bind:address already in use

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

close(server_sockfd);
close(client_sockfd);

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

ps -ef | grep tcpServerDemo
lsof -i:8888

后来查资料发现即使进程终止,socket也会有一个TIME-WAIT状态,它大概持续2-4分钟,当然也可能更长,过了这个时间就会释放这个端口号。
那么怎么才能立即启动而不是等待这个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 ;
    }

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

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

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

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

猜你喜欢

转载自blog.csdn.net/weixin_43466192/article/details/126350235
今日推荐