Я создаю простой чат-клиент, где клиенты присоединяются к серверу и отправляют ему сообщения, которые затем, в свою очередь, отправляют эти сообщения всем другим подключенным клиентам.
У меня проблема с выяснением того, как клиенты могут отправлять сообщения на сервер, а также одновременно получать входящие сообщения от других клиентов через сервер. Проблема, с которой я сталкиваюсь, состоит в том, что любой метод, который я нахожу для ввода данных, всегда приводит к зависанию потока (так как он ожидает ввода от пользователя).
Это верно и для прослушивания входящих данных, но я нашел способ тайм-аут ожидания, чтобы я мог зациклить его и сделать что-то перед тем, как увидеть, есть ли какие-либо данные, требующие повторной обработки.
Мой код клиента:
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;
}
Задача ещё не решена.
Других решений пока нет …