【发布时间】:2016-08-27 21:23:48
【问题描述】:
所以我有这个winsock 应用程序(一个服务器,能够接受多个客户端),在主线程中我设置套接字并创建另一个线程来监听客户端(listen_for_clients 函数)。
我还不断地从主线程中的设备接收数据,然后将其连接到 Client 对象(BroadcastSample 函数)的字符数组(缓冲区)。目前,我为每个连接的客户端(ProcessClient 函数)创建一个线程,在其中我初始化一个 Client 对象并将其推送到客户端的全局向量,之后每当相应缓冲区中的缓冲区时,我都会通过套接字向该客户端发送数据Client 对象超过 4000 个字符。
有没有一种方法可以将数据从主线程发送到单独的客户端线程,这样我就不必使用结构/类(如果我想发送已经累积的数据,也可以发送绿灯),而且如果我要保留一个全局对象容器,有什么好方法可以从中删除断开连接的客户端对象,而不会因为另一个线程正在使用同一个容器而导致程序崩溃?
struct Client{
int buffer_len;
char current_buffer[5000];
SOCKET s;
};
std::vector<Client*> clientBuffers;
DWORD WINAPI listen_for_clients(LPVOID Param)
{
SOCKET client;
sockaddr_in from;
int fromlen = sizeof(from);
char buf[100];
while(true)
{
client = accept(ListenSocket,(struct sockaddr*)&from,&fromlen);
if(client != INVALID_SOCKET)
{
printf("Client connected\n");
unsigned dwThreadId;
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, &ProcessClient, (void*)client, 0, &dwThreadId);
}
}
closesocket(ListenSocket);
WSACleanup();
ExitThread(0);
}
unsigned __stdcall ProcessClient(void *data)
{
SOCKET ClientSocket = (SOCKET)data;
Client * a = new Client();
a->current_buffer[0] = '\0';
a->buffer_len = 0;
a->s = ClientSocket;
clientBuffers.push_back(a);
char szBuffer[255];
while(true)
{
if(a->buffer_len > 4000)
{
send(ClientSocket,a->current_buffer,sizeof(a->current_buffer),0);
memset(a->current_buffer,0,5000);
a->buffer_len = 0;
a->current_buffer[0] = '\0';
}
}
exit(1);
}
//function below is called only in main thread, about every 100ms
void BroadcastSample(Sample s)
{
for(std::vector<Client*>::iterator it = clientBuffers.begin(); it != clientBuffers.end(); it++)
{
strcat((*it)->current_buffer,s.to_string);
(*it)->buffer_len += strlen(s.to_string);
}
}
【问题讨论】:
-
每个socked线程为您做什么?
send(socked,buffer,size,0)通话需要很长时间吗?我认为拥有这些线程并没有什么收获。 -
@Jfevold:作为一般规则,如果您有多个客户端,所有 I/O 都应该在单独的线程中完成或异步完成。否则,一个行为不端的客户可能会导致一切都停止。
-
如果您使用的是最新版本的 C++,您可能应该使用它的线程支持,这无疑包括线程安全队列等。如果您想使用 Windows API,interlocked singly linked lists 可能是一个合适的选择。
-
您正在迅速达到一个地步,即您正在发生太多复杂和异步事件,无法在多个线程中保持理智的跟踪。要么逻辑会让你崩溃,要么死锁会。根据您的要求,我将进行消息传递设计,其中只有一个线程专门用于运行状态机并维护客户端/缓冲区/其他列表。所有其他线程会将事件对象实例排队到它。这样的设计可能会引入更多的开销等,但具有可能实际可调试和无竞争/无死锁的优点。
-
当然,您可以使用大量锁并让线程以异步方式对多个数据项执行操作。小心和幸运,这可能会奏效,但这就像哭泣的天使一样:眨眼,你就会陷入不可预知的噩梦般的地狱,不断变化的失败。
标签: c++ multithreading sockets server winsock