我在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
中没有套接字值的字段。
答案 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
返回的SOCKET
。 accept()
表示已建立的连接从另一个对等方收到CLOSE_WAIT
,正在等待您发送FIN
并关闭FIN
句柄以进行连接。
修复该错误,您根本不需要使用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_ERROR
或SOCKET_ALIVE
您可以根据需要更改 timeout.tv_sec(1秒)。