我已经制作了Multi Client服务器,它可以向服务器接收和发送消息,服务器也可以向客户端发回消息,但我遇到的问题是,除非客户端A发送消息,否则客户端A将无法从客户端B接收消息向客户端发送和从客户端接收消息的
我已经尝试将std::getline(std::cin, ClientInput);
移动到代码中的不同位置,以便客户端能够看到消息,但我在代码中注意到while循环没有继续,因为有一种方法可以在不停止循环的情况下获得用户输入,从而可以发送和接收消息
这是客户端代码
int Client::OnCreate()
{
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo *result = NULL, *ptr = NULL, hints;
char sendbuf[] = "this is a test";
std::vector<SOCKET> ConnectedUser;
char recvbuf[DEFAULT_BUFLEN];
int iResult;
int recvbuflen = DEFAULT_BUFLEN;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %dn", iResult);
system("pause");
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo("localhost", DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed with error: %dn", iResult);
WSACleanup();
system("pause");
return 1;
}
// Attempt to connect to an address until one succeeds
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("socket failed with error: %ldn", WSAGetLastError());
WSACleanup();
system("pause");
return 1;
}
// Connect to server.
iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("Unable to connect to server!n");
WSACleanup();
system("pause");
return 1;
}
// Send an initial buffer
std::string ClientInput;
std::cout << "please send a message " << std::endl;
std::getline(std::cin, ClientInput);
do {
if (ClientInput.size() > 0)
{
//send user input to sever
iResult = send(ConnectSocket, ClientInput.c_str(), ClientInput.size(), 0);
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %dn", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
system("pause");
return 1;
}
printf("Bytes Sent: %dn", iResult);
if (iResult != SOCKET_ERROR)
{
//receive user input from sever
int iUserResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if (iUserResult > 0)
{
std::cout << "Client receive this message from sever t" << std::string(recvbuf, 0, iResult) << std::endl;
printf("Bytes received: %dn", iUserResult);
}
}
//will disconnect from the sever
if (iResult == SOCKET_ERROR)
{
printf("send failed with error: %dn", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
system("pause");
}
//will disconnect from the sever if user types in logoff
if (ClientInput == "logoff")
{
closesocket(ConnectSocket);
WSACleanup();
printf("Connection closing goodbye severn");
system("pause");
}
//close connection if the no user input
if (iResult == 0) {
printf("Connection closedn");
iResult = shutdown(ConnectSocket, SD_SEND);
}
}
std::getline(std::cin, ClientInput);
} while (ClientInput.size() > 0);
// cleanup
closesocket(ConnectSocket);
system("pause");
WSACleanup();
return 0;
}```
这是服务器代码
std::vector<SOCKET> ConnectedUser;
std::vector<int> UserInt;
unsigned __stdcall ClientSession(void *data)
{
char recvbuf[DEFAULT_BUFLEN];
int recvbufleng = DEFAULT_BUFLEN;
int iResult;
int iSendResult;
SOCKET ClientSocket = (SOCKET)data;
struct addrinfo *result = NULL, hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
do
{
iResult = recv(ClientSocket, recvbuf, recvbufleng, 0);
///iResult = recv(ClientSocket, recvbuf, sizeof(Player), 0);
std::cout << iResult << std::endl;
if (iResult > 0) {
for (int i = 0; i < ConnectedUser.size(); i++) {
std::cout << "send message to "<< ConnectedUser[i] << std::endl;
//iSendResult = send(ClientSocket, recvbuf, iResult, 0);
iSendResult = send(ConnectedUser[i], recvbuf, iResult, 0);
//ConnectedUser.clear();
//iSendResult = sendto(ConnectedUser[i], recvbuf, iResult, 0, (sockaddr*)&hints, sizeof(hints));
}
std::cout << "ClientSocket" << ClientSocket << std::endl;
if (iSendResult == SOCKET_ERROR)
{
printf("send failed with error: %d n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
printf("Received Message %.*sn", iResult, recvbuf);
}
else if (iResult == 0)
{
printf("connection closing.... n");
std::cout << "user logged off" << ClientSocket << std::endl;
}
else
{
printf("recv failed with error: %d n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
} while (iResult > 0);
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
closesocket(ClientSocket);
}
int Sever::OnCreate()
{
WSADATA wsaData;
int iResult;
SOCKET ClientSocket = INVALID_SOCKET;
//send to
char recvbuf[DEFAULT_BUFLEN];
int recvbufleng = DEFAULT_BUFLEN;
int iSendResult;
struct addrinfo *result = NULL, hints;
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 = WSAStartup(MAKEWORD(2, 2), &wsaData);
//create the winsocket
if (iResult != 0) {
printf("WSAStartup failed: %dn, iResult");
return 1;
}
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed: %dn", iResult);
WSACleanup();
return 1;
}
SOCKET ListenSocket = INVALID_SOCKET;
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("error at socket(): %dn", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
iResult = bind(ListenSocket, result->ai_addr, int(result->ai_addrlen));
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
if (listen(ListenSocket, SOMAXCONN) == SOCKET_ERROR) {
printf("Listen failed with error: %d n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
// Create the master file descriptor set and zero it
fd_set master;
FD_ZERO(&master);
FD_SET(ListenSocket, &master);
fd_set copy = master;
int socketCount = select(0, ©, nullptr, nullptr, nullptr);
std::cout << " socketCount "<< socketCount << std::endl;
//// Send an initial buffer
//if (socketCount == 0) {
// std::string SeverInput;
// std::cout << "input Server command" << std::endl;
// std::getline(std::cin, SeverInput);
//
// if (SeverInput == "exit")
// {
// closesocket(ClientSocket);
// WSACleanup();
// printf("Connection closing goodbye severn");
// }
//}
for (int i = 0; i < socketCount; i++)
{
SOCKET sock = copy.fd_array[i];
if (sock == ListenSocket)
{
//// Accept a new connection
while ((ClientSocket = accept(ListenSocket, NULL, NULL))) {
if (ClientSocket == INVALID_SOCKET) {
printf("Accept failed with error: %d n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
/* Messtotal.push_back(ClientSocket + "n");*/
// Add the new connection to the list of connected clients
FD_SET(ClientSocket, &master);
ConnectedUser.push_back(ClientSocket);
std::cout << "client:" << ClientSocket <<" has arrived on sever" <<std::endl;
// Create a new thread for the accepted client (also pass the accepted client socket).
unsigned threadID;
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, &ClientSession, (void*)ClientSocket, 0, &threadID);
}
}
}
WSACleanup();
printf("Server shutting down ");
return 0;
```}
将std::getline(std::cin,ClientInput(移动到客户端代码中循环中的任何位置都不会有帮助,因为getline((是一个阻塞调用。在这种情况下,您应该在客户端代码中使用线程。
您需要使用while循环在客户端代码中创建一个新线程。在这个线程中,您将收到来自另一个客户端的消息。
客户端代码中的主线程将处理来自getline((的用户输入,并通过while循环中的send函数发送消息。
例如,在您的客户端代码中,您可以创建这样的线程:
m_hTrhead = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)processMessage, (LPVOID)ConnectSocket, CREATE_SUSPENDED, 0);
if (m_hTrhead == NULL)
{
printf("Failed to create thread for receiving messages , error code : %ld n", GetLastError());
return false;
}
线程将在函数processMessage中处理消息,如下所示:
DWORD WINAPI Socket::processMessage(LPVOID lpParam)
{
SOCKET ConnectSocket= reinterpret_cast <SOCKET>(lpParam);
while (WSAGetLastError() != WSAECONNRESET)
{
int iUserResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if (iUserResult > 0)
{
std::cout << "Client receive this message from sever t" << std::string(recvbuf, 0, iResult) << std::endl;
printf("Bytes received: %dn", iUserResult);
}
}
}
请注意,也存在非阻塞套接字(因此线程不会在recv或send函数处停止(。非阻塞套接字的函数名称相同,但必须将套接字本身设置为非阻塞。
u_long mode = 1; // enable non-blocking socket
ioctlsocket(sock, FIONBIO, &mode);
你可以在这里阅读更多关于