1. 阻塞模型
2. 阻塞+多线程
3. select
4. 异步IO
5. IOCP
6. epoll
7. Reactor和Proactor
文章目录
在上一篇【C++ Socket编程】(一)阻塞模型 中,阻塞模型每次只能处理一个连接的数据收发,但其实socket的accept、send和recv是可以独立的,可以不需要在执行其中一个操作时阻塞另一个操作。所以我们可以在不同的线程中分别处理各个操作。
阻塞+多线程的服务端
在每次accept后,创建一个线程处理新的客户端连接。
/*
sock_server_block_thread.cpp
阻塞模型+多线程
单纯的阻塞模型服务端一次只能处理单个连接
当接收到客户端连接后,创建一个线程去处理此客户端的请求,可解决一次只处理一个客户端连接的问题
*/
#include <iostream>
using namespace std;
#include <winsock2.h>
#include <stdio.h>
#include <process.h>
#pragma comment(lib, "ws2_32.lib")
#define SERVERPORT 9000
#define MSG_BUF_SIZE 128
#define BACK_LOG 10 // 经过三次握手,但还没有accept的最大连接数,达到最大值后将拒绝连接
unsigned int Proc(void *args);
int main(int argc, char **argv)
{
WSADATA wsaData;
SOCKET sockServer;
SOCKADDR_IN addrServer;
SOCKADDR_IN addrClient;
WSAStartup(MAKEWORD(2, 2), &wsaData);
//创建服务端socket
sockServer = socket(AF_INET, SOCK_STREAM, 0);
addrServer.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //INADDR_ANY表示任何IP
addrServer.sin_family = AF_INET;
addrServer.sin_port = htons(SERVERPORT); //绑定端口
//绑定socket
bind(sockServer, (SOCKADDR *)&addrServer, sizeof(SOCKADDR));
//Listen监听端
listen(sockServer, BACK_LOG); // 等待连接数目 SOMAXCONN
printf("server start:\nlistening...\n");
int len = sizeof(SOCKADDR);
HANDLE h_thread;
while (true)
{
//会阻塞进程,直到有客户端连接上来为止
SOCKET sockClient = accept(sockServer, (SOCKADDR *)&addrClient, &len);
printf("socket client connected : %s:%d\r\n", inet_ntoa(addrClient.sin_addr), addrClient.sin_port);
//创建一个线程处理新的连接
_beginthreadex(nullptr, 0, Proc, (void*)sockClient, 0, nullptr);
}
//关闭socket
closesocket(sockServer);
WSACleanup();
return 0;
}
unsigned int Proc(void *args)
{
char sendBuf[MSG_BUF_SIZE]; //发送至客户端的字符串
char recvBuf[MSG_BUF_SIZE]; //接受客户端返回的字符串
SOCKET sockClient = (SOCKET )args;
int recv_size = -1;
int send_result = -1;
do
{
memset(recvBuf, 0, MSG_BUF_SIZE);
//阻塞等待接收数据
recv_size = recv(sockClient, recvBuf, MSG_BUF_SIZE, 0);
if (recv_size > 0)
{
//打印客户端数据
sprintf(sendBuf, " %d this is sock server", &sockClient);
send_result = send(sockClient, recvBuf, MSG_BUF_SIZE, 0);
printf("%d %s %d\n", &sockClient, recvBuf, send_result);
if (send_result == SOCKET_ERROR)
{
cerr << "Failed to send message to client!Error code: " << ::GetLastError() << "\n";
closesocket(sockClient);
system("pause");
return 1;
}
}
else if (recv_size == 0)
{
cout << "connection closed..." << endl;
}
else
{
printf("%d socket closed,recv_size : %d\r\n", &sockClient, recv_size);
closesocket(sockClient);
break;
}
} while (recv_size > 0);
recv_size = shutdown(sockClient, SD_SEND);
if (recv_size == SOCKET_ERROR)
{
cerr << "Failed to shutdown the client socket!Error code: " << ::GetLastError() << "\n";
closesocket(sockClient);
system("pause");
return 1;
}
return 0;
}
还是用上一节的sock_client_bulk.exe测试,效果好一点,感觉效果不明显,可能是我的姿势不对。