我需要从TCP服务器发送简单数据到循环连接的多个客户端。 前两个客户端的send命令成功,但当我尝试连接第三个客户端时,它失败并出现错误10038。
代码非常简单,在第一个连接上创建一个线程,然后对于其他连接,将打开的套接字添加到全局数组中。 线程将相同的数据(字符串" hello")发送给所有连接的客户端(通过localhost)。
我犯了一个小错误吗?有什么我不知道的吗?为什么它仅适用于两个连接?
编辑:
我想强调一点,我发布的代码只是一个例子而且它不是真正的服务器,它只想表现出一种我不明白的奇怪症状,我的意思是,为什么当第三个客户端连接到服务器发送失败,错误10038(WSAENOTSOCK)?
我的测试(在同一台机器上)会发生什么:
为什么第三次连接失败?我究竟做错了什么?
我的代码:
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/timeb.h>
int nclients = 0;
SOCKET lClient[10];
CRITICAL_SECTION m_cs;
DWORD WINAPI ClientThread(LPVOID lpParam)
{
int i;
char buffer[20] = "Hello\n";
while(1) {
EnterCriticalSection(&m_cs);
for (i=0;i<nclients;i++) {
if (lClient[i] != INVALID_SOCKET) {
if( send(lClient[i], buffer , strlen(buffer) , 0) < 0) {
printf("socket() failed: %d\n", WSAGetLastError());
nclients--;
}
}
}
LeaveCriticalSection(&m_cs);
Sleep(200);
}
return 0;
}
int main(int argc, char **argv) {
WSADATA wsd;
SOCKET sListen, sClient;
int iAddrSize;
HANDLE hThread;
DWORD dwThreadId;
struct sockaddr_in local, client;
int i,iPort;
InitializeCriticalSection(&m_cs);
for (i=0;i<10;i++) lClient[i] = INVALID_SOCKET;
iPort = 5000;
if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
{
printf("Failed to load Winsock!\n");
return 1;
}
// Create our listening socket
//
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (sListen == SOCKET_ERROR)
{
printf("socket() failed: %d\n", WSAGetLastError());
return 1;
}
// Select the local interface and bind to it
//
local.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
local.sin_family = AF_INET;
local.sin_port = htons(iPort);
if (bind(sListen, (struct sockaddr *)&local,
sizeof(local)) == SOCKET_ERROR)
{
printf("bind() failed: %d\n", WSAGetLastError());
return 1;
}
listen(sListen, 8);
//
// In a continous loop, wait for incoming clients. Once one
// is detected, create a thread and pass the handle off to it.
//
while (1)
{
iAddrSize = sizeof(client);
sClient = accept(sListen, (struct sockaddr *)&client,&iAddrSize);
if (sClient == INVALID_SOCKET)
{
printf("accept() failed: %d\n", WSAGetLastError());
break;
}
printf("Accepted client: %s:%d\n",inet_ntoa(client.sin_addr), ntohs(client.sin_port));
if (nclients == 0) {
hThread = CreateThread(NULL, 0, ClientThread, 0, 0, &dwThreadId);
EnterCriticalSection(&m_cs);
lClient[nclients] = sClient;
nclients++;
LeaveCriticalSection(&m_cs);
}
else {
EnterCriticalSection(&m_cs);
lClient[nclients] = sClient;
nclients++;
LeaveCriticalSection(&m_cs);
}
if (hThread == NULL)
{
printf("CreateThread() failed: %d\n", GetLastError());
break;
}
CloseHandle(hThread);
}
closesocket(sListen);
WSACleanup();
return 0;
}
答案 0 :(得分:0)
您的线程循环在遇到错误时未正确更新阵列。并且您的主代码不会处理所有客户端断开连接然后新客户端连接的可能性,因此可能会创建多个线程。
请改为尝试:
bool keepRunning = true;
DWORD WINAPI ClientThread(LPVOID lpParam)
{
const char buffer[] = "Hello\n";
const int buflen = strlen(buffer) ;
while (keepRunning)
{
EnterCriticalSection(&m_cs);
int i = 0;
while ((i < nclients) && (keepRunning))
{
if (send(lClient[i], buffer, buflen, 0) == SOCKET_ERROR)
{
int err = WSAGetLastError();
closesocket(lClient[i]);
if (err != WSAENOTSOCK)
printf("Failed to send data to a client! Error: %d\n", err);
for (int j = i+1; j < nclients; ++j)
lClient[j-1] = lClient[j];
--nclients;
}
else
{
++i;
}
}
LeaveCriticalSection(&m_cs);
Sleep(200);
}
return 0;
}
int main(int argc, char **argv)
{
WSADATA wsd;
SOCKET sListen, sClient;
int iAddrSize;
HANDLE hThread = NULL;
DWORD dwThreadId = 0;
struct sockaddr_in local, client;
int iPort;
InitializeCriticalSection(&m_cs);
for (int i = 0; i < 10; ++i) lClient[i] = INVALID_SOCKET;
iPort = 5000;
int ret = WSAStartup(MAKEWORD(2,2), &wsd);
if (ret != 0)
{
printf("Failed to load Winsock! Error: %d\n", ret);
return 1;
}
// Create our listening socket
//
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (sListen == SOCKET_ERROR)
{
printf("Failed to create listening socket! Error: %d\n", WSAGetLastError());
WSACleanup();
return 1;
}
// Select the local interface and bind to it
//
local.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
local.sin_family = AF_INET;
local.sin_port = htons(iPort);
if (bind(sListen, (struct sockaddr *)&local, sizeof(local)) == SOCKET_ERROR)
{
printf("Failed to bind listening socket! Error: %d\n", WSAGetLastError());
closesocket(sListen);
WSACleanup();
return 1;
}
// Start listening for clients
//
if (listen(sListen, 8) == SOCKET_ERROR)
{
printf("Failed to listen for clients! Error: %d\n", WSAGetLastError());
closesocket(sListen);
WSACleanup();
return 1;
}
//
// In a continuous loop, wait for incoming clients. Once
// one is detected, create a thread to process clients.
//
while (keepRunning)
{
iAddrSize = sizeof(client);
sClient = accept(sListen, (struct sockaddr *)&client, &iAddrSize);
if (sClient == INVALID_SOCKET)
{
printf("Unable to accept a client! Error: %d\n", WSAGetLastError());
break;
}
EnterCriticalSection(&m_cs);
if (nclients == 10)
{
LeaveCriticalSection(&m_cs);
closesocket(sClient);
printf("Ignoring client: %s:%d, too many clients already connected\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
continue;
}
lClient[nclients] = sClient;
++nclients;
LeaveCriticalSection(&m_cs);
printf("Accepted client: %s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
if (!hThread)
{
hThread = CreateThread(NULL, 0, &ClientThread, 0, 0, &dwThreadId);
if (hThread == NULL)
{
printf("Unable to create thread! Error: %u\n", GetLastError());
break;
}
}
}
keepRunning = false;
if (hThread != NULL)
{
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}
for (int i = 0; i < nclients; ++i)
closesocket(lClient[i]);
closesocket(sListen);
WSACleanup();
return 0;
}