Winsock — Как получать и отправлять данные одновременно?

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

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

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

Мой код клиента:

int main()
{
WSADATA wsaData;

SOCKET ConnectionSocket = INVALID_SOCKET;

addrinfo  *result = NULL;
addrinfo  hints;
addrinfo  *ptr    = NULL;

fd_set    set;

HANDLE    hThread;

string username;

unsigned  threadID;
int       iResult;
int       sent_msg;
int fileD;

char      send_buffer[DEFAULT_BUFLEN];
char      recieve_buffer[DEFAULT_BUFLEN];

bool      connected = true;

int       error_code;

timeval   timeout_period;

/*
* Initalize WinSock.
*/
if (init_WinSock(wsaData)) { return 1; };

/*
* Zeroize structure.
*/
ZeroMemory(&hints, sizeof(hints));

hints.ai_family   = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;

getaddrinfo("192.168.1.77", DEFAULT_PORT, &hints, &result);

ptr = result;

ConnectionSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);

iResult = connect(ConnectionSocket, ptr->ai_addr, ptr->ai_addrlen);

freeaddrinfo(result);

if (iResult == SOCKET_ERROR) {
error_code = WSAGetLastError();

closesocket(ConnectionSocket);

cout << "Unable to connect!";
WSACleanup();
system("Pause >> null");
return 1;
}

cout << "Connected." << endl;
cout << "Please choose a username: ";

do {
cin.getline(send_buffer, (int)strlen(send_buffer));

if ((int)strlen(send_buffer) > 10) {
cout << "Name too long! Choose again: ";
memset(send_buffer, 0, DEFAULT_BUFLEN);
}
} while ((int)strlen(send_buffer) > 10);

username = send_buffer;

/*
* Initial connection. Send ID/username.
*/
send(ConnectionSocket, send_buffer, (int)strlen(send_buffer), 0);

memset(recieve_buffer, 0, DEFAULT_BUFLEN);

while (iResult != SOCKET_ERROR) {
FD_ZERO(&set); /* clear the set */
FD_SET(ConnectionSocket, &set);
FD_SET(0, &set);

error_code = select(ConnectionSocket + 1, &set, NULL, NULL, NULL);
error_code = WSAGetLastError();

if (FD_ISSET(0, &set)) {
cin.getline(send_buffer, DEFAULT_BUFLEN);

cout << username << ": " << send_buffer << endl;

send(ConnectionSocket, send_buffer, DEFAULT_BUFLEN, 0);

memset(send_buffer, 0, DEFAULT_BUFLEN);
} else if (FD_ISSET(ConnectionSocket, &set)) {
iResult = recv(ConnectionSocket, recieve_buffer, DEFAULT_BUFLEN, 0);
recieve_buffer[iResult] = '\0';

cout << "Placeholder: " << recieve_buffer << endl;

}
}

closesocket(ConnectionSocket);

cout << "\n\nDisconnected...";

system("pause >> null");

return 0;
}

Код сервера:

unsigned __stdcall handle_client(void *data)
{
client_socket_data_type client;

char                    recvbuf[DEFAULT_BUFLEN];

timeval                 timeout_period;

fd_set                  set;

int iResult;

// mutex                   mtx;

client = *((client_socket_data_type *)data);

memset(recvbuf, 0, DEFAULT_BUFLEN);

timeout_period.tv_sec  = MAX_TIMEOUT;
timeout_period.tv_usec = 0;

FD_ZERO(&set); /* clear the set */
FD_SET(client.client_socket, &set);

iResult = select(client.client_socket, &set, NULL, NULL, &timeout_period);

while (iResult != SOCKET_ERROR) {
if (iResult > 0) {
recv(client.client_socket, recvbuf, DEFAULT_BUFLEN, 0);

if (recvbuf != " ") {
for each (SOCKET connected_clients in client.connected_clients)
{
if (client.client_socket != connected_clients) {
send(connected_clients, recvbuf, DEFAULT_BUFLEN, 0);
memset(recvbuf, 0, DEFAULT_BUFLEN);
}
}
}
}
iResult = select(client.client_socket, &set, NULL, NULL, &timeout_period);
}

clients--;

return 0;
}

int main()
{
WSADATA wsaData;

SOCKET    listen_socket = INVALID_SOCKET;
SOCKET    client_socket = INVALID_SOCKET;

struct addrinfo *result = NULL;
struct addrinfo  hints;

client_socket_data_type client;

HANDLE    hThread;

unsigned  threadID;

char recv_buffer[DEFAULT_BUFLEN];

void *ctx;

int error_code;
int iResult;/*
* Initalize WinSock.
*/
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}

/*
* Zeroize structure.
*/
ZeroMemory(&hints, sizeof(hints));

hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;

iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}

listen_socket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (listen_socket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}

iResult = bind(listen_socket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(listen_socket);
WSACleanup();
return 1;
}

/*
* Finished setup. Clear structure.
*/
freeaddrinfo(result);

/*
* Listen on port for inbound connections.
*/
iResult = listen(listen_socket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(listen_socket);
WSACleanup();
return 1;
}

cout << "Server initalized successfully. Waiting on client connections. 0/" << MAX_CLIENTS << endl;

memset(recv_buffer, 0, DEFAULT_BUFLEN);

while (true) {
while (clients < MAX_CLIENTS) {
client_socket = SOCKET_ERROR;

while (client_socket == SOCKET_ERROR) {
client_socket = accept(listen_socket, NULL, NULL);
}

client.client_socket = client_socket;

clients++;

cout << "Client connected. Number of connected clients: " << clients << '/' << MAX_CLIENTS << endl;

/*
* Initial connection. Asking for name.
*/

recv(client.client_socket, recv_buffer, DEFAULT_BUFLEN, 0);

cout << "Debug, name recieved. Name is: " << recv_buffer << endl;

/*
* Name put inside structure.
*/
client.client_name = recv_buffer;

ctx = &client;

hThread = (HANDLE)_beginthreadex(NULL, 0, &handle_client, ctx, 0, &threadID);

client.connected_clients.push_back(client.client_socket);

memset(recv_buffer, 0, DEFAULT_BUFLEN);
}
}

return 0;
}

0

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru