7.3 一个连接一个线程模型
正因为最原始的服务器结构不支持并发,随着计算机引入多线程模型后,软件开发者想出了另外一种服务器结构,即给每一个客户端连接创建一个线程,这样多个线程就可以并行执行了,可以同时为多个客户端服务。
示例代码如下:
//侦听线程
UINT WINAPI MyMainThread(LPVOID lPvoid)
{
LOG_NORMAL("Start MyMainThread successfully, ThreadID = %u.", ::GetCurrentThreadId());
UINT nThreadID = 0;
SOCKET sListenSocket = (SOCKET)lPvoid;
SOCKET sClientSocket = 0;
while (1)
{
//等待客户连接
sockaddr_in clientAddr = { 0 };
int clientAddrLength = sizeof(clientAddr);
if ((sClientSocket = accept(sListenSocket, (struct sockaddr*)&clientAddr, &clientAddrLength)) == INVALID_SOCKET)
break;
LOG_NORMAL("New client connected: %s:%d", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
//启动客户签到线程
_beginthreadex(NULL, 0, MyChildThread, (LPVOID)sClientSocket, 0, &nThreadID);
}
closesocket(sListenSocket);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//接收连接线程
UINT WINAPI MyChildThread(LPVOID lPvoid)
{
LOG_NORMAL("Start MyChildThread successfully, ThreadID = %u.", ::GetCurrentThreadId());
//交易处理
SOCKET sClientSocket = (SOCKET)lPvoid;
CLIENTITEM clientItem = { 0 };
int nCmd = HandleClientMain(sClientSocket, &clientItem);
LOG_NORMAL("Client cmd = %d", nCmd);
if (nCmd == -1)
closesocket(sClientSocket);
else if (nCmd == CONN_MAIN)
LoginTrans(sClientSocket, &clientItem);
else
InterTrans(sClientSocket, &clientItem, nCmd);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
上述代码中,在某个线程 MyMainThread 中(可以是主线程也可以是非主线程)调用 accept 接受客户端连接,成功接受连接后,为每一个新连接创建一个工作线程(MyChildThread)。当然,为了能让工作线程可以正常处理所负责的连接上的来往数据,利用线程函数参数将 socket 句柄传给工作线程(注意上述代码中参数 sClientSocket 的传递方法)。
上次更新: 2024/07/08, 00:14:14