socket模型处理多个客户端

最近学完了简单的socket编程,发现其实socket的网络编程其实并没有什么难度,只是简单的函数调用,记住客户端与服务端的步骤,写起来基本没有什么问题。 在服务器程序的设计中,一个服务器不可能只相应一个客户端的链接,为了响应多个客户端的链接,需要使用多线程的方式,每当有一个客户端连接进来,我们就开辟一个线程,用来处理双方的交互(主要是利用recv或者recvfrom用于收发信息),由于但是在网络中可能出现这样一种情况:由于处理比较复杂,下一条信息到来之后,上一条信息的处理还没有完成,这样信息太多了之后系统的缓冲占满之后可能会发生丢包的现象,所以为了解决这个问题,需要另外再开一个线程,专门用来处理接收到的数据,这样总共至少有3个线程,主线程,收发信息的线程,处理线程;这样可能也不完整,处理的操作种类多了的话可能需要根据不同的请求来开辟不同的线程用来处理这一类请求,下面是实现这一思路的部分代码: 全局变量:

DWORD WINAPI AcceptThread(LPVOID lpParameter);
DWORD WINAPI RecvThread(LPVOID lpParameter);

DWORD g_nAcceptID = 123;
DWORD g_nRecvID = 234;

HANDLE g_hAccpetThread;
HANDLE g_hRecvThread;

主线程函数:

int _tmain(int argc, _TCHAR* argv[])
{
    WSADATA wd;
    WSAStartup(MAKEWORD(2, 2), &wd);

    SOCKET sockListen = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
    if (INVALID_SOCKET == sockListen)
    {
        cout << "创建侦听套接字失败,错误码为:" << WSAGetLastError() << endl;
        return -1;
    }

    SOCKADDR_IN srvAddr = { 0 };
    srvAddr.sin_family = AF_INET;
    srvAddr.sin_port = htons(6666);
    srvAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    if (SOCKET_ERROR == bind(sockListen, (SOCKADDR*)&srvAddr, sizeof(SOCKADDR)))
    {
        cout << "绑定失败,错误码为:" << WSAGetLastError() << endl;
        WSACleanup();
        return -1;
    }

    if (SOCKET_ERROR == listen(sockListen, 5))
    {
        cout << "侦听失败,错误码为:" << WSAGetLastError() << endl;
        WSACleanup();
        return -1;
    }

    while (true)
    {
        SOCKET sockConn = accept(sockListen, NULL, 0);
        if (INVALID_SOCKET == sockConn)
        {
            cout << "本次连接失败,即将进入下一次连接,错误码为:" << WSAGetLastError() << endl;
            closesocket(sockConn);
            closesocket(sockListen);
            WSACleanup();
            continue;
        }

        g_hAccpetThread = CreateThread(NULL, 0, AcceptThread, &sockConn, 0, &g_nAcceptID);
    }

    WaitForSingleObject(g_hAccpetThread, INFINITE);
    WSACleanup();
    return 0;
}

收发数据函数:

DWORD WINAPI AcceptThread(LPVOID lpParameter)
{
    cout << "有客户端连接进来" << endl;
    SOCKET sockConn = *(SOCKET*)lpParameter;
    while (true)
    {
        char *pszBuf = (char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE, 255);
        if (SOCKET_ERROR == recv(sockConn, pszBuf, 255, 0))
        {
            cout << "接受数据失败,错误码为:" << WSAGetLastError() << endl;
            cout << "准备进行下一次接受数据....." << endl;
            continue;
        }

        g_hRecvThread = CreateThread(NULL, 0, RecvThread, pszBuf, 0, &g_nRecvID);
        WaitForSingleObject(g_hRecvThread, INFINITE);
        if (0 == strcmp("exit", pszBuf))
        {
            cout << "正在断开与该客户端的连接" << endl;
            HeapFree(GetProcessHeap(), 255, pszBuf);
            return 0;
        }
    }

    return 0;
}

信息处理子线程: DWORD WINAPI RecvThread(LPVOID lpParameter) { cout << “接受到客户端的数据:” << (char*)lpParameter << endl; return 0; } 虽说这个解决了多个客户端与服务器通信的问题,但是这样写确定也很明显:所有的与客户端通信的socket都有程序员自己管理,无疑加重了程序员的负担;每有一个连接都需要创建一个线程,当有大量的客户端连接进来开辟的线程数是非常多的,线程是非常耗资源的,所以为了解决这些问题就提出了异步的I/O模型,它们解决了这些问题,由系统管理套接字,不要要人为的一个个管理,同时不需要开辟多个线程来处理与客户端的连接,我们可以将线程主要用于处理客户端的请求上;

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏一只程序汪的自我修养

手把手教你用.NET Core写爬虫

自从上一个项目58HouseSearch从.NET迁移到.NET core之后,磕磕碰碰磨蹭了一个月才正式上线到新版本。

394120
来自专栏ml

MFC学习之窗口基础

                          WinMain函数  1、句柄(HANDLE):{ 1. 定义:资源的标识 2. 句柄的作用: 操作系统通过...

31760
来自专栏美团技术团队

Android App包瘦身优化实践

随着业务的快速迭代增长,美团App里不断引入新的业务逻辑代码、图片资源和第三方SDK,直接导致APK体积不断增长。包体积增长带来的问题越来越多,如CDN流量费用...

56130
来自专栏安恒网络空间安全讲武堂

赛前福利①最新2018HITB国际赛writeup

FIRST 距离“西湖论剑杯”全国大学生网络空间安全技能大赛只有10天啦! 要拿大奖、赢offer,那必须得来点赛前练习定定心啊~这不,讲武堂就拿到了2018H...

48550
来自专栏黑泽君的专栏

day54_BOS项目_06

第一步:根据提供的 业务受理.pdm 文件生成建表文件 bos_qp.sql 第二步:由于业务受理.pdm 文件中有伪表,所以我们需要修改生成的建表文件,修改如...

10720
来自专栏ml

unbuntu系统( PC机 )中安装360wifi步骤

少说废话,每一步都经过验证:   1.  首先查看一下当前使用的linux版本: gxjun@gxjun:~$ uname -r 4.8.0-59-generi...

36630
来自专栏林德熙的博客

WPF 轻量级 MVVM 框架入门 2.1.2 安装项目要求创建主页面找到 ViewModel通过附加属性找到 ViewModel跳转页面跳转命令自定义命令

本文告诉大家如何使用本金鱼的 MVVM 轻量框架。 一个好的框架是不需要解释就可以让大家使用,但是本金鱼没有这个能力,所以就写了这个文章告诉大家如何使用。

16920
来自专栏恰童鞋骚年

.NET Core微服务之基于IdentityServer建立授权与验证服务(续)

上一篇我们基于IdentityServer4建立了一个AuthorizationServer,并且继承了QuickStartUI,能够成功获取Token了。这一...

32450
来自专栏圣杰的专栏

Asp.net mvc 知多少(一)

本系列主要翻译自《ASP.NET MVC Interview Questions and Answers 》- By Shailendra Chauhan,想...

29270
来自专栏张高兴的博客

张高兴的 Windows 10 IoT 开发笔记:使用 Lightning 中的软件 PWM 驱动 RGB LED

36160

扫码关注云+社区

领取腾讯云代金券