问题描述
我用 C++ 编写了一个服务器程序,并用 C++ 编写了一个客户端程序.两者都工作正常,但是当一个客户端与服务器通信时,其他客户端无法连接到同一台服务器.如果假设当我关闭客户端 1 时,那么我的第二个客户端也无法连接到服务器.我已经用多个线程启动了我的服务器以连接到多个客户端,但只有一个客户端正在连接.
I have written a server program in C++ and also a client program in C++.Both are working fine but when if one client is communicating with the server then other client can't get connected to the same server. If suppose when I close the client 1 then also my 2nd client can't connect to the server. I have started my Server with multiple threads to connect to multiple clients but only one client is connecting.
我的服务器程序:
#include <iostream>
#include <winsock2.h>
#include <Windows.h>
#include <process.h>
#include <thread>
#pragma comment(lib,"ws2_32.lib")
static const int num_of_threads = 2;
void client_disconnected(SOCKET Socket);
void start_server()
{
WSADATA WsaDat;
if(WSAStartup(MAKEWORD(2,2),&WsaDat)!=0)
{
std::cout<<"WSA Initialization failed!\r\n";
WSACleanup();
system("PAUSE");
}
SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(Socket==INVALID_SOCKET)
{
std::cout<<"Socket creation failed.\r\n";
WSACleanup();
system("PAUSE");
}
SOCKADDR_IN serverInf;
serverInf.sin_family=AF_INET;
serverInf.sin_addr.s_addr=INADDR_ANY;
serverInf.sin_port=htons(8888);
if(bind(Socket,(SOCKADDR*)(&serverInf),sizeof(serverInf))==SOCKET_ERROR)
{
std::cout<<"Unable to bind socket!\r\n";
WSACleanup();
system("PAUSE");
}
listen(Socket,3);
SOCKET TempSock=SOCKET_ERROR;
while(TempSock==SOCKET_ERROR)
{
std::cout<<"Waiting for incoming connections...\r\n";
Sleep(5000);
TempSock=accept(Socket,NULL,NULL);
}
// If iMode!=0, non-blocking mode is enabled.
u_long iMode=1;
ioctlsocket(Socket,FIONBIO,&iMode);
Socket=TempSock;
std::cout<<"Client connected!\r\n\r\n";
// Main loop
for(;;)
{
int nError=WSAGetLastError();
if(nError!=WSAEWOULDBLOCK&&nError!=0)
{
client_disconnected(Socket);
break;
}
char *szMessage="Welcome to the server!\r\n";
send(Socket,szMessage,strlen(szMessage),0);
Sleep(2000);
}
}
void client_disconnected(SOCKET Socket)
{
std::cout<<"Client disconnected!\r\n";
// Shutdown our socket
shutdown(Socket,SD_SEND);
// Close our socket entirely
closesocket(Socket);
WSACleanup();
}
int main()
{
//starting multiple threads for invoking server
std::thread threads[num_of_threads];
//This statement will launch multiple threads in loop
for (int i = 0; i < num_of_threads; ++i) {
threads[i] = std::thread(start_server);
Sleep(2000);
}
for (int i = 0; i < num_of_threads; ++i) {
threads[i].join();
}
return 0;
}
我的客户计划:
#include <iostream>
#include <winsock2.h>
#include <Windows.h>
#include <process.h>
#include "client.h"
#pragma comment(lib,"ws2_32.lib")
void MultipleClient :: receiveToClient(void*data)
{
WSADATA WsaDat;
if(WSAStartup(MAKEWORD(2,2),&WsaDat)!=0)
{
std::cout<<"Winsock error - Winsock initialization failed\r\n";
WSACleanup();
system("PAUSE");
}
// Create our socket
SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(Socket==INVALID_SOCKET)
{
std::cout<<"Winsock error - Socket creation Failed!\r\n";
WSACleanup();
system("PAUSE");
}
// Resolve IP address for hostname
struct hostent *host;
if((host=gethostbyname("localhost"))==NULL)
{
std::cout<<"Failed to resolve hostname.\r\n";
WSACleanup();
system("PAUSE");
}
// Setup our socket address structure
SOCKADDR_IN SockAddr;
SockAddr.sin_port=htons(8888);
SockAddr.sin_family=AF_INET;
SockAddr.sin_addr.s_addr=*((unsigned long*)host->h_addr);
// Attempt to connect to server
if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr))!=0)
{
std::cout<<"Failed to establish connection with server\r\n";
WSACleanup();
system("PAUSE");
}
// If iMode!=0, non-blocking mode is enabled.
u_long iMode=1;
ioctlsocket(Socket,FIONBIO,&iMode);
// Main loop
for(;;)
{
// Display message from server
char buffer[1000];
memset(buffer,0,999);
int inDataLength=recv(Socket,buffer,1000,0);
std::cout<<buffer;
//end client when server is disconnected
int nError=WSAGetLastError();
if(nError!=WSAEWOULDBLOCK&&nError!=0)
{
std::cout<<"Winsock error code: "<<nError<<"\r\n";
std::cout<<"Server disconnected!\r\n";
// Shutdown our socket
shutdown(Socket,SD_SEND);
// Close our socket entirely
closesocket(Socket);
break;
}
Sleep(2000);
}
WSACleanup();
system("PAUSE");
}
class Client{
public:
static unsigned int __stdcall receiveMessageThread(void *p_this)
{
MultipleClient* mc = static_cast<MultipleClient*>(p_this);
mc-> receiveToClient(p_this); // Non-static member function!
return 0;
}
void startThread()
{
HANDLE myhandleA;
myhandleA = (HANDLE)_beginthreadex(0,0,&Client::receiveMessageThread,this,0, 0);
WaitForSingleObject(myhandleA, INFINITE);
}
};
int main(void)
{
Client *c = new Client;
c->startThread();
return 0;
}
请帮助我如何使多个客户端与单个服务器连接.示例代码将非常有用(抱歉问了).
Please help me how to make multiple clients to connect with a single server. A sample code will be very useful(sorry for asking).
推荐答案
你在线程间分配工作的方式是错误的.
Your way of distributing work among threads is wrong.
您希望一个线程打开侦听套接字并在那里等待传入连接.请注意,每个端口不能有多个侦听套接字,因此您绝对不希望多个线程同时尝试侦听同一个端口.
You want one thread to open the listening socket and wait for incoming connections there. Note that you cannot have more than one listening socket per port, so you definitely don't want multiple threads trying to listen on the same port simultaneously.
如果有连接进来,accept
会给你一个新的套接字对象.您仍然拥有等待新连接的原始侦听套接字,但您现在还有一个 第二 套接字,其中已经建立了到客户端的连接.
If a connection comes in, accept
will give you a new socket object. You still have the original listening socket, which waits for new connections, but you also have a second socket now with an already established connection to a client.
现在您可以拆分工作:让一个线程返回对原始套接字调用 listen
并等待新连接,而另一个线程则获取新套接字并执行必要的 I/O 以与客户互动.
Now you can split the work: Have one thread go back to calling listen
on the original socket and await new connections, while the other thread grabs the new socket and performs the necessary I/O to interact with the client.
在这个简单的方案中,每个客户端连接总是有一个线程,另外还有一个用于侦听套接字的线程.由于所有这些线程都将花费大量时间来等待网络 I/O 完成,因此您可以使用异步 I/O 在较少(甚至单个)线程之间共享工作负载,但这稍微复杂一些完成,所以我建议你把它留到第二稿.
In this simple scheme, you will always have one thread per client connection plus an additional thread for the listening socket. Since all of these threads will spent a large amount of time just waiting for network I/O to complete, you can use asynchronous I/O to share the workload between fewer (or even a single) threads, but that is slightly more complex to pull off, so I'd suggest you leave that for a second draft.
这篇关于如何在 Windows - Visual Studio 上使用 C++ 将多个客户端连接到单个服务器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!