我想更改我用来接受无限量客户的socket class。目前它允许一个客户端,并且一旦该客户端断开服务器退出。
#include "stdafx.h"
#include "mySocket.h"
#include "myException.h"
#include "myHostInfo.h"
void main()
{
#ifdef WINDOWS_XP
// Initialize the winsock library
WSADATA wsaData;
try
{
if (WSAStartup(0x101, &wsaData))
{
myException* initializationException = new myException(0,"Error: calling WSAStartup()");
throw initializationException;
}
}
catch(myException* excp)
{
excp->response();
delete excp;
exit(1);
}
#endif
// get local server information
myHostInfo uHostAddress;
string localHostName = uHostAddress.getHostName();
string localHostAddr = uHostAddress.getHostIPAddress();
cout << "------------------------------------------------------" << endl;
cout << " My local host information:" << endl;
cout << " Name: " << localHostName << endl;
cout << " Address: " << localHostAddr << endl;
cout << "------------------------------------------------------" << endl;
// open socket on the local host
myTcpSocket myServer(PORTNUM);
cout << myServer;
myServer.bindSocket();
cout << endl << "server finishes binding process... " << endl;
myServer.listenToClient();
cout << "server is listening to the port ... " << endl;
// wait to accept a client connection.
// processing is suspended until the client connects
cout << "server is waiting for client connecction ... " << endl;
myTcpSocket* client; // connection dedicated for client communication
string clientHost; // client name etc.
client = myServer.acceptClient(clientHost);
cout << endl << "==> A client from [" << clientHost << "] is connected!" << endl << endl;
while(1)
{
//Send message to the client
client->sendMessage(std::string("Test"));
// receive from the client
string clientMessageIn = "";
int numBytes = client->recieveMessage(clientMessageIn); //Get message from client, non-blocking using select()
if ( numBytes == -99 ) break;
if(clientMessageIn != "")
{
std::cout << "received: " << clientMessageIn << std::endl; //What did we receive?
/* Do somethign with message received here */
}
}
#ifdef WINDOWS_XP
// Close the winsock library
try
{
if (WSACleanup())
{
myException* cleanupException = new myException(0,"Error: calling WSACleanup()");
throw cleanupException;
}
}
catch(myException* excp)
{
excp->response();
delete excp;
exit(1);
}
#endif
}
如何更改main()函数以便它始终等待新客户端连接,一旦它们这样做,为他(客户端)或新的处理程序套接字创建一个新线程(无论可能是什么) )。
我确实发现this线程是提供信息的,但我缺乏必要的套接字知识,无法在上面的代码中实际实现它。
答案说明When doing socket communication, you basically have a single listener socket for all incoming connections, and multiple handler sockets for each connected client.
所以我猜测我的代码;
myTcpSocket myServer(PORTNUM);
myServer.bindSocket();
myServer.listenToClient();
将是listener socket
但是我在哪里/如何分配连接到handler socket
的客户端?
我很抱歉没有能够表现出更多的努力,我不喜欢懒惰。但是对于我搜索过的所有时间以及由此产生的反复试验,我没有太多可展示的内容。
答案 0 :(得分:3)
这个想法很简单,你只需要等待传入的连接,一旦被接受,就将套接字传递给一个线程。
您需要将从accept
返回的新套接字传递给新线程;你可以每次生成一个新线程并通过参数传递套接字,或者将套接字添加到一堆工作线程使用的共享队列中。
这是我编写的一个简单代理的一些代码,它使用了线程的boost和一个围绕套接字函数的简单OOP包装。
主线程 - 它创建4个空闲等待的工作线程 要发出信号的信号量。它将所有接受的连接推送到全局队列:
// Global variables
const size_t MAX_THREADS = 4;
queue<Socket> socketBuffer; // Holds new accepted sockets
boost::mutex queueGuard; // Guards the socketBuffer queue
semaphore queueIndicator; // Signals a new connection to the worker threads
bool ctrlc_pressed = false;
// Inside the main function...
boost::thread_group threads;
for(int i = 0; i < MAX_THREADS; i++)
{
threads.create_thread(boost::bind(&threadHandleRequest, i+1));
}
while(!ctrlc_pressed)
{
// wait for incoming connections and pass them to the worker threads
Socket s_connection = s_server.accept();
if(s_connection.valid())
{
boost::unique_lock<boost::mutex> lock(queueGuard);
socketBuffer.push(s_connection);
queueIndicator.signal();
}
}
threads.interrupt_all(); // interrupt the threads (at queueGuard.wait())
threads.join_all(); // wait for all threads to finish
s_server.close();
线程代码:
bool threadHandleRequest(int tid)
{
while(true)
{
// wait for a semaphore counter > 0 and automatically decrease the counter
try
{
queueIndicator.wait();
}
catch (boost::thread_interrupted)
{
return false;
}
boost::unique_lock<boost::mutex> lock(queueGuard);
assert(!socketBuffer.empty());
Socket s_client = socketBuffer.front();
socketBuffer.pop();
lock.unlock();
// Do whatever you need to do with the socket here
}
}
希望有所帮助:)
答案 1 :(得分:0)
在进行套接字通信时,您基本上只有一个侦听器 所有传入连接的套接字,以及用于的多个处理程序套接字 每个连接的客户端。
这就是重点。您需要一个单独的线程用于侦听器套接字。当它收到传入的请求时,它会启动另一个处理程序套接字的线程(它将创建并发送响应),然后再次开始监听(你需要一个循环)。
我肯定会使用线程而不是分叉。在Windows上的AFAIK只有cygwin能够分叉,但我不会将cygwin用于这样的程序。