【C++ Socket编程】(二)阻塞+多线程

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测试,效果好一点,感觉效果不明显,可能是我的姿势不对。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值