我正在创建一个简单的聊天客户端,客户端加入服务器并向其发送消息,然后将消息发送给所有其他连接的客户端。
我遇到的问题是弄清楚如何让客户端能够向服务器发送消息,同时还能够通过服务器同时接收来自其他客户端的入站消息。我遇到的问题是,我发现输入的任何方法总是使线程挂起(因为它等待用户的输入)。
在收听传入数据时也是如此,但是我找到了一种方法来延迟等待,这样我就可以循环它,并在看到是否有任何数据需要再次处理之前做一些事情。 / p>
我的客户代码:
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;
}