Socket error 10053,10054究竟是怎么引起的

REFER TO: http://bbs.csdn.net/topics/360024280

Q: 谁能贴点代码,能稳定的重现这2个socket error吗?我就是想知道,出现这2个问题时,TCP协议栈到底遇到什么异常情况了。贴2段能稳定重现10053的代码。

先贴客户端的:

    WORD    VersionRequested;
    WSADATA WsaData;

    VersionRequested = MAKEWORD(2, 2);

    if (WSAStartup(VersionRequested, &WsaData))
        return -1;

    SOCKET SocketServer  = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    SOCKADDR_IN AddrServer;
    AddrServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    AddrServer.sin_port             = htons(9999);
    AddrServer.sin_family           = AF_INET;

    // 连接服务器
    if (0 != connect(SocketServer, (SOCKADDR *)&AddrServer, sizeof(SOCKADDR)))
    {
        closesocket(SocketServer);
        return false;
    }

    int err = 0;
    char temp[] = "hello, server";
    int rs = send(SocketServer, temp, sizeof(temp) + 1, 0);

    char buff[1024] = {0};
    rs = recv(SocketServer, buff, sizeof(buff), 0);

        // 下面这2句代码如果注释掉,后面的recv就能正解的返回0。如果不注释掉,recv就会返回-1,
         // 并得到10053这个错误
    rs = send(SocketServer, temp, sizeof(temp) + 1, 0);
    err = WSAGetLastError();

    rs = recv(SocketServer, buff, sizeof(buff), 0);
    err = WSAGetLastError();

    system("pause");
    return 0;

这个是服务器的

    WORD    VersionRequested;
    WSADATA WsaData;

    VersionRequested = MAKEWORD(2, 2);

    if (WSAStartup(VersionRequested, &WsaData))
    {
        printf("加载socket库失败!\n");
        return -1;
    }

    // 监听来自浏览器的请求
    SOCKET SockServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    SOCKADDR_IN AddrClient;
    AddrClient.sin_family      = AF_INET;
    AddrClient.sin_addr.s_addr = INADDR_ANY;
    AddrClient.sin_port        = htons(9999);

    if (SockServer == INVALID_SOCKET)
    {
        printf("socket初始化失败!\n");
        closesocket(SockServer);
        WSACleanup();
        return -1;
    }

    if (bind(SockServer, (sockaddr*)&AddrClient, sizeof(AddrClient)) != 0)
    {
        printf("socket绑定失败!\n");
        closesocket(SockServer);
        WSACleanup();
        return -1;
    }

    if (listen(SockServer, 10) != 0)
    {
        printf("socket监听失败!\n");
        closesocket(SockServer);
        WSACleanup();
        return -1;
    }

    while (1)
    {
        SOCKET NewSocket = accept(SockServer, NULL, NULL);
        if (INVALID_SOCKET == NewSocket)
        {
            closesocket(NewSocket);
            continue;
        }
        else
        {
            struct linger so_linger;
            so_linger.l_onoff  = 1;
            so_linger.l_linger = 30;
            setsockopt(NewSocket ,SOL_SOCKET, SO_LINGER, (const char*)&so_linger, sizeof(so_linger)); 
        }

        char buff[1024];
        int rs = recv(NewSocket, buff, sizeof(buff), 0);

        char temp[] = "hello, client";
        rs = send(NewSocket, temp, sizeof(temp) + 1, 0);

        closesocket(NewSocket);
    }

A:出现10053的原因是因为在你执行这次send的时候对端已经执行过closesocket了,而发送的数据还是被成功的推入了发送缓冲区中,因此返回了0,此时你可能还没得到FIN消息,而紧接着recv这边就得到了对端关闭socket的FIN消息,因此此时需要放弃发送缓冲中的数据,异常终止连接,所以得到了10053错误:您的主机中的软件中止了一个已建立的连接。

而为什么又能得到10054的错误号,原因应该在于你设置了SO_LINGER了,一但设置了它,则有一个等待时间,在该等待时间内可以处理发送缓冲区的数据,一但超时或者发送缓冲都被发送完并被确认,则服务端有可能发送RST消息而不是FIN,此时客户端就应该得到重置错误,也就是10054。

不同的系统对SO_LINGER的实现方式不一样,得到的结果也不一样,不知道按我这样解释是否对你有帮助。如果我有理解错误,欢迎大家指正。

 

posted @ 2013-04-28 10:47  金石开  阅读(8907)  评论(0编辑  收藏  举报