2016-05-03 3 views
3

У меня есть приложение winsock (сервер, способный принимать несколько клиентов), где в основном потоке я настраиваю сокет и создаю другой поток, где я слушаю клиентов (listen_for_clients функция).Передача данных в другой поток в приложении C++ winsock

Я также постоянно получаю данные с устройства в основном потоке, которое впоследствии конкатенация на массивы символов (буферы) объектов Client (BroadcastSample). В настоящее время я создаю поток для каждого подключенного клиента (ProcessClient), где я инициализирую объект Client и нажимаю его на глобальный вектор клиентов, после которого я отправляю данные этому клиенту через сокет, когда буфер в соответствующем объекте Client превышает 4000 персонажи.

Есть ли способ отправить данные из основного потока в отдельные потоки клиентов, поэтому мне не нужно использовать structs/classes (также для отправки зеленого света, если я хочу отправить уже накопленные данные) и также, если я собираюсь хранить глобальный контейнер объектов, что является хорошим способом удалить отключенный клиентский объект из него без сбоев программы, потому что другой поток использует тот же контейнер?

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); 
    } 
} 
+0

Какие темы для носок используются для вас? вызов 'send (socked, buffer, size, 0)' занимает много времени? Я не думаю, что вы что-то набираете, имея эти темы. – Jfevold

+0

@ Jfevold: как правило, если у вас несколько клиентов, все операции ввода-вывода должны выполняться отдельными потоками или асинхронно. В противном случае один неудачный клиент мог бы привести все к кричащей остановке. –

+0

Если вы используете достаточно недавнюю версию C++, вам, вероятно, следует использовать поддержку потоков, которая, без сомнения, включает поточно-безопасные очереди и т. П. Если вы хотите использовать Windows API, [заблокированные отдельные списки] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms684121 (v = vs.85) .aspx) может быть подходящий вариант. –

ответ

1

This link имеет некоторую документацию Microsoft на мьютексах MS-стиле (muticies?).

This other link содержит информацию о мьютексе.

Мьютексы - это общий механизм защиты данных, к которым обращаются несколько потоков. Существуют структуры данных со встроенной безопасностью потоков, но, по моему опыту, у них обычно есть оговорки, которые вы в конечном итоге пропустите. Это всего лишь мои два цента.

Кроме того, для записи вы не должны использовать strcat, а скорее strncat. Кроме того, если один из ваших потоков обслуживания клиентов обращается к одному из этих буферов после того, как strncat перезаписывает старый '\0', но перед тем, как он добавит новый, вы получите переполнение буфера (прочитайте прошлый конец выделенного буфера).

Мьютексы также решат вашу текущую проблему ожидания ожидания. Я сейчас не рядом с компилятором Windows, или я бы попытался помочь больше.