我正在编写一个服务器应用程序,它等待ServerSocket对象并创建连接套接字。 每个连接都有一个SocketListener和一个用于传输数据的SocketSender。
每个SocketListener都是一个单独的线程。当客户端断开连接时,SocketListener向ServerSocket发送一条消息,告知它正在关闭,以便ServerSocket可以从列表中清除该连接的句柄。
但是,不知道为什么SocketListener线程没有收到该消息。我试图缩小消息过滤器,但没有运气。有人可以帮我这个。
DWORD ServerSocket::m_ThreadFunc() {
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed\n");
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Resolve the server address and port
iResult = getaddrinfo(NULL, DEFAULT_PORT_STR, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed\n");
WSACleanup();
return 1;
}
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("socket failed\n");
freeaddrinfo(result);
WSACleanup();
return 1;
}
// Setup the TCP listening socket
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("bind failed\n");
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("listen failed\n");
closesocket(ListenSocket);
WSACleanup();
return 1;
}
// allow listener thread to report back its state
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
//force create message queue
PeekMessage(&msg, NULL, WM_USER, WM_USER + 100, PM_NOREMOVE);
printf("Listing for clients on port %s \n", DEFAULT_PORT_STR);
while (listening) {
// Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket != INVALID_SOCKET) {
printf("Client connected\n");
sender = new SocketSender(ClientSocket);
listener = new SocketListener(ClientSocket, this->m_threadId);
printf("Listener created\n");
listener->setSender(sender);
listener->startThread();
printf("Listener started\n");
listenerList.push_back(listener);
senderList.push_back(sender);
printf("Listener list size: %d \n", listenerList.size());
printf("Listener pushed to list\n");
//delete socket data if listener close itself due to connection lost or disconnect.
}
else {
int error = WSAGetLastError();
printf("accept failed\n");
switch (error) {
case 10093:
listening = false;
try {
closesocket(ListenSocket);
}
catch (...) {}
return 1;
}
}
printf("Check message queue for thread message\n");
//check thread message queue
//GetMessage(&msg, NULL, 0, 0); //this blocks untill a message is get.
PeekMessage(&msg, NULL, WM_USER, WM_USER + 100, PM_REMOVE);
if (msg.message == WM_USER + 1)
{
//ProcessCustomMessage(msg);
m_deleteListener((SocketListener*)msg.wParam);
printf("Recieved message from ThreadID: %d \n", msg.wParam);
}
printf("Recieved message from ThreadID: %d \n", msg.message);
printf("Server socket complete 1 loop\n");
}
return 0;
}
DWORD SocketListener::m_ThreadFunc() {
listening = true;
rapidxml::xml_document<> doc;
printf("Start thread with ID: %d \n", this->m_threadId);
printf("Parent Thread ID: %d \n", this->_iParentID);
while (listening) {
int iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
printf("Bytes received: %d\n", iResult);
recvbuf[iResult - 1] = 0; // null terminate the string according to the length
// The message spec indicates the XML will end in a "new line"
// character which can be either a newline or caraiage feed
// Search for either and replace with a NULL to terminate
if (recvbuf[iResult - 2] == '\n' || recvbuf[iResult - 2] == '\r')
recvbuf[iResult - 2] = 0;
try {
doc.parse<0>(&recvbuf[0]);
HandleXMLMessage(&doc);
}
catch (...) {}
}
else {
printf("Thread %d is being closed, sending signal to parent (%d)\n", this->m_threadId, this->_iParentID);
if (PostThreadMessage(this->_iParentID, WM_APP + 1, NULL, NULL) == 0)
{
printf("Client cant send Message before closing the conn ! \n");
printf("Last error %d", GetLastError());
}
else {
printf("Client sent Closing Message successfully \n");
}
closesocket(ClientSocket);
return 1;
}
}
printf("Server terminate connection\n");
printf("Thread %d is closed, sending signal to parent (%d)\n", this->m_threadId,this->_iParentID);
PostThreadMessage(this->_iParentID, WM_USER + 1, (WPARAM)this->m_threadId, NULL);
return 0;
}
非常感谢。
答案 0 :(得分:0)
accept函数是一个阻塞调用,所以看起来在接受第一个连接后你的循环卡在
ClientSocket = accept(ListenSocket, NULL, NULL);
在下一次建立连接之前,不检查线程消息队列。
您还需要检查PeekMessage的返回结果,以了解消息是否实际被查看,否则msg变量将包含垃圾。