2.1 网络编程 异步网络库zvnet

2.1.1 网络io与io多路复用select/poll/epoll

  1. 搭建一个简单的服务端
cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>

int main()
{
    // 1. create socket
    int listenFd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serverAddr.sin_port = htons(2000);
    // 2. bind socket
    int flag = bind(listenFd, (struct sockaddr *)&serverAddr, sizeof(serverAddr));

    if (-1 == flag)
    {
        printf("bind error: %s\n", strerror(errno));
        return -1;
    }

    // 3. listen
    listen(listenFd, 10);
    struct sockaddr_in clientAddr;
    int len = sizeof(clientAddr);

    int clientFd;

    char buff[1024];
    while(1)
    {
        memset(buff, 0, sizeof(buff));
        // 4. accept client connection
        clientFd = accept(listenFd,(struct sockaddr*)&clientAddr,&len);

        // 5. recv data from client
        recv(clientFd, buff, sizeof(buff), 0);
        printf("recv data: %s\n", buff);

        // 6. send data to client
        memset(buff, 0, sizeof(buff));
        sprintf(buff, "hello client, I have received your data");
        send(clientFd, buff, strlen(buff), 0);
        close(clientFd);
    }

    close(listenFd);


    return 0;
}

上述代码可以循环的接收客户端连接,并且每一个客户端拥有一次和服务端收发数据的过程。但是有一个致命的确定,比如client1 client2 client3依此连接到服务端(先连接不发数据),此时会出现什么情况呢?如果我client3 client2 client1依此给server发消息,但只有当client1发出消息之后,client3和client2才会收到消息。

分析原因:client1 client2 client3依此连接到服务端时,程序阻塞在recv上,那么其他的client只有三次握手成功,并且阻塞在TCP队列上,并不能建立tcp连接。

  1. 改用多线程的方式
cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
#include <bits/pthreadtypes.h>

void handle_task(void* arg)
{
    int clientFd = *(int*)arg;
    char buff[1024];
    memset(buff, 0, sizeof(buff));
    while(1)
    {
        memset(buff, 0, sizeof(buff));
        int count = recv(clientFd, buff, sizeof(buff), 0);
        printf("recv data: %s\n", buff);

        if(0 == count)
        {
            printf("client closed connection\n");
            break;
        }

        memset(buff, 0, sizeof(buff));
        sprintf(buff, "hello client, I have received your data");
        send(clientFd, buff, strlen(buff), 0);
    }
    close(clientFd);
}

int main()
{
    // 1. create socket
    int listenFd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serverAddr.sin_port = htons(2000);
    // 2. bind socket
    int flag = bind(listenFd, (struct sockaddr *)&serverAddr, sizeof(serverAddr));

    if (-1 == flag)
    {
        printf("bind error: %s\n", strerror(errno));
        return -1;
    }

    // 3. listen
    listen(listenFd, 10);
    struct sockaddr_in clientAddr;
    int len = sizeof(clientAddr);

    int clientFd;

    char buff[1024];
    static int count = 0;
#if 0
    while(1)
    {
        memset(buff, 0, sizeof(buff));
        // 4. accept client connection
        clientFd = accept(listenFd,(struct sockaddr*)&clientAddr,&len);

        printf("accept client connection, count: %d\n", ++count);
        // 5. recv data from client
        recv(clientFd, buff, sizeof(buff), 0);
        printf("recv data: %s\n", buff);

        // 6. send data to client
        memset(buff, 0, sizeof(buff));
        sprintf(buff, "hello client, I have received your data");
        send(clientFd, buff, strlen(buff), 0);
        close(clientFd);
    }
#elif 1
    // with multi thread
    while(1)
    {
        // 4. accept client connection
        clientFd = accept(listenFd,(struct sockaddr*)&clientAddr,&len);
        pthread_t thid;
        pthread_create(&thid, NULL, (void *)handle_task, (void *)&clientFd);
    }

#endif


    close(listenFd);


    return 0;
}

上述代码在不断开tcp连接时候可以一直进行通信。

弊端:1. 如果tcp连接过多,超过10个之后,server将不能服务新的tcp连接。

  1. 如果tcp连接"占着茅坑不拉屎",那么是对server资源的一种浪费。
相关推荐
云布道师1 分钟前
阿里云 Tablestore 为 Hermes Agent 构建记忆系统最佳实践
网络·人工智能·阿里云
雨浓YN9 分钟前
GKMLT通讯工具箱(WPF MVVM) - 02-Modbus RTU 与 TCP 报文格式、原理与CRC校验
网络·网络协议·tcp/ip
雨浓YN12 分钟前
GKMLT通讯工具箱(WPF MVVM) - 01-网口/串口通讯与 ModBus RTU/TCP
网络·网络协议·tcp/ip
feng_you_ying_li1 小时前
linux之shell的进阶补充和基础IO流的介绍
linux·运维·服务器
志栋智能2 小时前
运维超自动化:构建弹性IT架构的关键支撑
运维·服务器·网络·人工智能·架构·自动化
草莓熊Lotso3 小时前
Vibe Coding 时代:LangChain 与 LangGraph 全链路解析
linux·运维·服务器·数据库·人工智能·mysql·langchain
网安情报局9 小时前
除了 CDN,DDoS 攻击还有哪些更有效的防护方式?
网络
代码AI弗森9 小时前
一文理清楚“算力申请 / 成本测算 / 并发评估”
java·服务器·数据库
Promise微笑9 小时前
2026年国产替代油介损测试仪:油介损全场景解决方案与技术演进
大数据·网络·人工智能
^—app56686610 小时前
游戏运存小启动不起来临时解决方法
运维·服务器