Как мне преобразовать этот блокирующий режим ввода-вывода в перекрывающийся режим ввода-вывода на языке c в Windows?
Я учусь делать сокет-программирование и многопоточное программирование на C на Windows. Я разработал проект, в котором будет три типа узлов для резервного копирования (сервер, клиент и узел хранения). Я создал следующее, чтобы иметь один сервер и несколько клиентов и узлов хранения. Сервер должен создать два вида потоков на основе типа клиента, запрашивающего услугу (чтобы быть явным обычным клиентом или узлом хранения). Я использую блокирующий режим ввода / вывода. Структура кода выглядит следующим образом:
Сервер:
int main()
{
//initialization and other things
while ((new_socket = accept(srv_sock, (struct sockaddr *)&client, &c)) != INVALID_SOCKET)
{
_beginthreadex(0, 0, handle_client, &new_socket, 0, 0);
}
}
uint32_t __stdcall handle_client(void *data)
{
SOCKET* sock = (SOCKET*)data;
SOCKET client_sock = *sock;
//other
recv_size = recv(client_sock, header_buf, HDR_LEN, 0);
//fixed length header
if (!strncmp(connect_with, "storageNode", strlen(connect_with)))
//check if client is a normal client or a storage node
{
_beginthreadex(0, 0, handle_storage_node, sock, 0, 0);
return 0;
}
else
{
//continue with request from normal client
}
}
uint32_t __stdcall handle_storage_node(void *data)
{
SOCKET* sock_SN = (SOCKET*)data;
SOCKET str_node_sock = *sock_SN;
//continue with request from storage node
}
Основная причина, среди прочего, для меня, чтобы захотеть изменить его на перекрывающийся ввод-вывод, заключается в том, что иногда (вероятно, один раз в тысячу раз) сообщение от обычного клиента заканчивается как сообщение от узла хранения, и наоборот. Я думаю, что причина в том, что winsock не является строго потокобезопасным. Плюс как новичок я хочу научиться делать это по-другому. Итак, какой должна быть эквивалентная структура для реализации перекрывающегося ввода-вывода? И как мне остановить доставку сообщений не в ту ветку?
PS: - Я новичок, успокойся!
1 ответ
Ваша проблема не в режиме перекрытия или нет. Дело в том, что ваша программа действует на недействительных данных.
В таких строках
_beginthreadex(0, 0, handle_client, &new_socket, 0, 0);
Вы передаете адрес переменной в стеке новому потоку. Этот адрес будет за пределами итерации цикла while. И, скорее всего, будет использоваться для хранения следующего дескриптора сокета, когда в следующий раз успешно выполнится accept.
Чтобы это исправить, вы можете выделить в куче каждый экземпляр сокета и передать эту функцию вашему рабочему потоку.
Перекрытое большинство просто все усложнит. Если вы не знаете, зачем вам это нужно, вам нет смысла его использовать.