面向连接的Socket服务端关闭问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向连接的Socket服务端关闭问题相关的知识,希望对你有一定的参考价值。

我在电脑上写了两个进程,一个是服务器,一个是客户端,建立的是面向连接的socket,但是当第一次双方通信完成后,我用ctl+c关闭服务端,然后马上重启服务端进程,会发现此时服务端进程bind失败,等一段时间后再重启服务端进程,bind成功,难道是面向链接的socket的关闭需要消耗一段时间吗?这个应该走的是TCP协议吧?
难道是TCP关闭连接要四次握手的原因吗?

因为,你把服务端进程关闭,已经与客户端建立好的tcp连接当前还没有完全关闭。当前服务端的tcp连接应该处于FIN_WAIT2状态,虽然该tcp连接已经与进程之间没有关系了(当前连接处于orphaned),但是操作系统还是会为这个连接维持内核的数据结构,而该连接的local port就是服务端的listen port,所以当你用socket去bind这个port的时候,操作系统会提示你说 Address already in use 。FIN_WAIT2状态的连接有定时器,应该和TIME_WAIT的时间长度相同,都是2MSL。超过了这段时间后,FIN_WAIT2的连接就会被操作系统移除。同样local port就不会被占用了,这样bind就能够成功了。追问

谢谢,采纳你的答案吧,感觉比较详细点

参考技术A 出现你描述现象的原因是:
Ctrl-C强制结束程序,导致程序异常退出,程序打开的Socket尚未关闭。换句话说,程序虽然退出了,但所使用Socket资源没有及时释放。
经过一段时间后,操作系统(内核)会强制释放异常退出程序未释放的Socket。这是操作系统提供的保护机制。

-------
这个现象与TCP关闭连接握手过程没有直接关系。追问

谢谢啦

基于UDP(面向无连接)的socket编程

说明:

本程序是基于windows socket的套接字库实现网络编程;
当WSAStartup函数调用成功后,在程序的最后都需要相应的调用WSACleanup函数
以便释放为该应用程序分配的资源,终止对WinSock动态库的使用。

在基于UDP的套接字编程来说,我们把先启动的一端称为接收端,即服务端。主动先发送数据的一端称为发送端,也就是客户端

基于UDP的服务器端流程

  1. 创建套接字(socket)
  2. 将套接字和IP地址、端口号绑定在一起(bind)
  3. 等待客户端发起数据通信(recvfrom/recvto)
  4. 关闭套接字

基于UDP的客户端流程

  1. 创建套接字(socket)
  2. 向服务器发起通信(recvfrom/recvto)
  3. 关闭套接字

基于UDP的socket编程流程图

基于UDP的socket编程不需要设置监听和发起/接收请求,可以直接相互通信,流程如下:

服务器端代码:

#include "stdafx.h"
#include <Winsock2.h>


int _tmain(int argc, _TCHAR* argv[])

    WORD dwVersionReq = MAKEWORD(1,1);
    WSAData wsData = 0;
    //加载套接字库
    if (0 != WSAStartup(dwVersionReq,&wsData))
    
        WSACleanup();
        return 0;
    
    //socket版本确认
    if (LOBYTE(wsData.wVersion) != 1 || HIBYTE(wsData.wVersion != 1))
    
        WSACleanup();
        return 0;
    

    //创建服务套接字
    SOCKET socketSrv = socket(AF_INET,SOCK_DGRAM,0/*自动选择协议*/);

    //对socket绑定端口号和IP地址
    SOCKADDR_IN addrServer;
    addrServer.sin_family = AF_INET;
    addrServer.sin_port = htons(6000);
    addrServer.sin_addr.S_un.S_addr = htonl(ADDR_ANY);
    bind(socketSrv,(SOCKADDR*)&addrServer,sizeof(addrServer));


    //保存client端socket信息
    SOCKADDR_IN addClient;
    int len = sizeof(SOCKADDR_IN);

    while (1)
    
        //等待并接收数据
        char szBuffer[100] = 0;
        recvfrom(socketSrv,szBuffer,100,0,(SOCKADDR*)&addClient,&len);
        printf("client->server:%s\\n",szBuffer);
        //发送数据
        char szSendBuf[100] = "this is server";
        sendto(socketSrv, szSendBuf, 100,0,(SOCKADDR*)&addClient,len);
    


    //关闭套接字
    closesocket(socketSrv);

    //关闭winsocket库
    WSACleanup();

    system("pause");

    return 0;

客户端代码:

#include "stdafx.h"
#include <Winsock2.h>

int _tmain(int argc, _TCHAR* argv[])

    //指定wind socket版本
    WORD dwVersionReq = MAKEWORD(1,1);
    WSAData wsData = 0;

    //加载套接字库dll
    if (0 != WSAStartup(dwVersionReq,&wsData))
    
        WSACleanup();
        return 0;
    

    //版本判断
    if (LOBYTE(wsData.wVersion) != 1 || HIBYTE(wsData.wVersion != 1))
    
        WSACleanup();
        return 0;
    

    //创建套接字
    SOCKET socketClient = socket(AF_INET,SOCK_DGRAM,0);

    //填充服务器socket信息
    SOCKADDR_IN addrServer;
    int nLength = sizeof(addrServer);
    addrServer.sin_family = AF_INET;
    //服务器的应用程序端口
    addrServer.sin_port = htons(6000);
    //服务器的IP地址,同一台电脑就是本地IP
    addrServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

    //发送数据
    char szClientBuf[100]= "this is client";
    sendto(socketClient,szClientBuf,100,0,(SOCKADDR*)&addrServer,nLength);
    
    //介绍数据
    char szRecvBuf[100] = 0;
    recvfrom(socketClient,szRecvBuf,100,0,(SOCKADDR*)&addrServer,&nLength);
    printf("server->client:%s\\n", szRecvBuf);

    //关闭套接字
    closesocket(socketClient);

    //关闭winsocket库
    WSACleanup();

    system("pause");
    return 0;

测试效果:

以上是关于面向连接的Socket服务端关闭问题的主要内容,如果未能解决你的问题,请参考以下文章

基于UDP(面向无连接)的socket编程

面向连接的网络应用程序--服务器端

Python学习之——Socket套接字(UDP连接)

:网络编程

socket创建服务端和客户端

UDP----socket通信