如何获得规范套接字的“CLOSE_WAIT”状态

时间:2017-11-20 16:49:42

标签: c++ api sockets networking

我在Visual Studio 2010上使用VC ++ 现在我遇到了一些问题。我认为这是一个如此愚蠢的问题,但我想得到一个明确的答案。

如何获得所选CLOSE_WAIT的{​​{1}}状态?

SOCKET

问题是// SocketThreadConn.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <WinSock.h> #include <Windows.h> #pragma comment(lib, "ws2_32.lib") #define PR_RECORED_TIME 10*1000 // (ms) BYTE* pByteCamData = NULL; INT nHeight = 900; INT nWidth = 1600; INT nSpect = 3; INT nSolution = nHeight * nWidth * nSpect; VOID SendRecoredData(SOCKET socket2operation); int _tmain(int argc, _TCHAR* argv[]) { pByteCamData = new BYTE[nSolution]; // <-- use [], not ()! //---------------------- // Initialize Winsock. WSADATA wsaData; int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); if (iResult != NO_ERROR) { wprintf(L"WSAStartup failed with error: %d\n", iResult); delete[] pByteCamData; return 1; } //---------------------- // Create a SOCKET for listening for // incoming connection requests. SOCKET ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ListenSocket == INVALID_SOCKET) { wprintf(L"socket failed with error: %d\n", WSAGetLastError()); WSACleanup(); delete[] pByteCamData; return 1; } //---------------------- // The sockaddr_in structure specifies the address family, // IP address, and port for the socket that is being bound. sockaddr_in service = {}; service.sin_family = AF_INET; service.sin_addr.s_addr = INADDR_ANY; // inet_addr("127.0.0.1"); service.sin_port = htons(27015); if (bind(ListenSocket, (SOCKADDR *) &service, sizeof(service)) == SOCKET_ERROR) { wprintf(L"bind failed with error: %d\n", WSAGetLastError()); closesocket(ListenSocket); WSACleanup(); delete[] pByteCamData; return 1; } //---------------------- // Listen for incoming connection requests. // on the created socket if (listen(ListenSocket, 1) == SOCKET_ERROR) { wprintf(L"listen failed with error: %d\n", WSAGetLastError()); closesocket(ListenSocket); WSACleanup(); delete[] pByteCamData; return 1; } //---------------------- // Accept the connection. wprintf(L"Waiting for client to connect...\n"); SOCKET AcceptSocket = accept(ListenSocket, NULL, NULL); if (AcceptSocket == INVALID_SOCKET) { wprintf(L"accept failed with error: %d\n", WSAGetLastError()); closesocket(ListenSocket); WSACleanup(); delete[] pByteCamData; return 1; } wprintf(L"Client connected.\n"); SendRecoredData(AcceptSocket); // <-- logic fix! // No longer need client socket closesocket(AcceptSocket); // <-- CLOSE_WAIT fix! // No longer need server socket closesocket(ListenSocket); WSACleanup(); delete[] pByteCamData; return 0; } VOID SendRecoredData(SOCKET socket2operation) { if(IsSocketAlive(socket2operation) == 0) return; INT nCountDown = 5; INT nSentData, nNumToSend; BYTE *pData; do { if (nCountDown == 0) { nCountDown = 5; pData = pByteCamData; nNumToSend = nSolution; while (nNumToSend > 0) <-- send() fix! { nSentData = send(socket2operation, (char*)pData, nNumToSend, 0); if (SOCKET_ERROR == nSentData) { wprintf(L"send failed with error: %d\n", WSAGetLastError()); return; } pData += nSentData; nNumToSend -= nSentData; } wprintf(L"Sent Camera Data OK [%d] Bytes\n", nSolution); } Sleep(PR_RECORED_TIME); --nCountDown; } while (TRUE); } INT IsSocketAlive(SOCKET socket2check) { if (socket2check == INVALID_SOCKET) return FALSE; INT nError_code = -1; INT nError_code_size = sizeof(nError_code); INT nRetValue = getsockopt(socket2check, SOL_SOCKET, SO_ERROR, (CHAR*)&nError_code, &nError_code_size); // if (nRetValue != -1) { // _tprintf(_T("Error getting socket error code : %d \n"), strerror(nRetValue)); } if (nError_code != 0) { _tprintf(_T("Socket error : %d \n"), strerror(nError_code)); } switch (nError_code) { case 0: return TRUE; break; case SOCKET_ERROR: return FALSE; default: return FALSE; } } 'ed'套接字被检查为活动套接字 当CLOSE_WAIT正在使用SocketThreadConn.exe时,虽然侦听套接字为while loop,但break loop不会CLOSE_WAIT

如何检查已接受的套接字ESTABLISHED

(此代码已由@Remy Lebeau更改)

我如何检查仍然ESTABLISHED未使用send()GetTcpTable()的套接字。

函数GetTcpTable()运行良好,但我必须使用它们的值(USHORT)查找套接字。 MIB_TCPTABLE中没有套接字值的字段。

3 个答案:

答案 0 :(得分:1)

SendRecoredData(ListenSocket);

那应该是

SendRecoredData(AcceptSocket);

这会导致你没有告诉我们的send()错误,而你永远不会关闭AcceptSocket。这就是造成CLOSE_WAIT状态的原因。您无需明确查找它们。只需修复你的错误。

答案 1 :(得分:1)

  

如何获得所选CLOSE_WAIT的{​​{1}}状态?

没有针对该特定目的的Winsock API。但是,您可以检索SOCKET的两个IP /端口对(通过getsockname()getpeername()),然后在GetTcpTable()或相关功能的输出中查找它们。这将为您提供当前状态,甚至是拥有过程。

但是,您的代码中存在导致SOCKET状态的错误 - 您没有关闭CLOSE_WAIT返回的SOCKETaccept()表示已建立的连接从另一个对等方收到CLOSE_WAIT,正在等待您发送FIN并关闭FIN句柄以进行连接。

state diagram

修复该错误,您根本不需要使用SOCKET

  

如何检查已接受的套接字GetTcpTable()

您也可以使用ESTABLISHED。但是,最好的方法是只通过连接执行实际的I / O,看看它是成功还是失败。您的GetTcpTable()功能不正确且无用。使用IsSocketAlive()的返回值来了解套接字是否仍然存活(因为您没有从客户端读取任何数据)。

话虽如此,您的代码中也存在其他错误。

您没有正确分配send()。您需要使用pByteCamData代替[]。您正在分配一个(),其中BYTE为其值,而不是nSolution个字节数组。

您正在将倾听nSolution传递给SOCKET,但您应该从SendRecoredData()传递SOCKET

accept()无法保证一次性发送所有请求的字节。它可以发送比请求更少的字节(这可能是因为您尝试一次发送> 4MB)。如果返回值小于请求的字节数,则必须再次调用send()以发送剩余字节。因此,在循环中调用send(),直到没有更多字节要发送。

尝试更像这样的事情:

send()

答案 2 :(得分:1)

#define SOCKET_ALIVE 10
#define SOCKET_DEAD 9

INT CheckSocketAlive(SOCKET socket2check)
{
    fd_set  fdR;
    struct  timeval timeout;
    timeout.tv_sec = 1;
    timeout.tv_usec = 0;
    FD_ZERO(&fdR);  
    FD_SET(socket2check, &fdR);
    switch (select(socket2check + 1, &fdR, NULL,NULL, &timeout))
    {  
    case SOCKET_ERROR:
        _tprintf(_T("\tError condition. Code : [%d]\n"), WSAGetLastError());
        return SOCKET_DEAD;
    case 0:
        return SOCKET_ALIVE;
    default:
        if ( FD_ISSET(socket2check, &fdR) )
        {
            _tprintf(_T("A read event has occurred on socket [socket2check].\n"));
            return SOCKET_DEAD;
        }
        break;
    }
}

您可以使用此功能获取所选套接字的状态。
但仅限SOCKET_ERRORSOCKET_ALIVE 您可以根据需要更改 timeout.tv_sec(1秒)