• tcp多线程处理多个客户端数据(linux)


    tcp多线程处理多个客户端数据(linux)

    thread 多线程 cpp

    头文件需要加入

    同时编译的时候,需要链接动态库 加入 -lpthread 参数

    代表链接pthread.so库

    链接动态库 需要-lxxxx参数

    thread 执行
    #include
    // thread 线程名(指向函数的地址,指向对象的指针)
    thread sth(&TcpThread::Main,thr)
    
    • 1
    • 2
    • 3
    逻辑

    首先创建用于生成连接的socket

    然后绑定端口号,接受的地址

    for(;😉

    {

    ​ accept() 接收到连接 生成用于单独连接的client_socket

    然后 将这个client_socket 送至一个自创的对象中,用于交流信息
    
    • 1

    ​ 线程包裹该对象,

    ​ 与子线程断开连接

    }

    代码

    socket_test.cpp

    // socket_test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
    //
    #include 
    #include 
    // 宏会在编译之前就执行,比如Linux时就不会有以下的代码
    #ifdef WIN32 // 当存在WIN32的宏时,会执行中间的
    #include 
    
    #else
    #include 
    #include           /* linux 引用这两个*/
    #include 
    #include 
    #include 
    #include 
    #endif
    
    #include 
    using namespace std;
    class TcpThread
    {
    public:
        int client_sock=0;
        TcpThread(int client_sock)
        {
            this->client_sock=client_sock;
        }
        ~TcpThread()
        {
            delete this;
        }
        void Main()
        {
            char buf[1024]={0};
            for(;;)
            {
                memset(buf,0,1024);
                int rec_len = recv(client_sock,buf,sizeof(buf)-1,0);
                cout<<rec_len<<endl;
                buf[rec_len]='\0';
                if(rec_len<=0)
                {
                    break;
                }
                cout<<"recive_len:"<<rec_len<<endl;
                cout<<"recive:"<<buf<<endl;
                int sendlen=send(client_sock,buf,1024,0);
                if(sendlen<=0)
                {
                    break;
                }
                if(strstr(buf,"quit")!=NULL)
                {
                    break;
                }
    
            }
            // 需要留一位放'/0' 
            // 返回已经收到的数据大小,指定的大小不一定是实际接受的大小,只是指定最大收多少数据,必须返回
            // 
            int rec_len = recv(client_sock,buf,sizeof(buf)-1,0);
            cout<<"recive_len:"<<rec_len<<endl;
            cout<<"recive:"<<buf<<endl;
            
            #ifdef WIN32
                closesocket(client_sock);
            #else
                close(client_sock);
            #endif
            // delete this;
        }
    
    };
    int main(int argc,char* argv[])
    {
    
        unsigned short port=8080;
        if (argc>1)
        {
            port=atoi(argv[1]);//atoi 字符串转化为数字
        }
    
        #ifdef WIN32 // 在linux中不需要以下的初始化
            // windows 调用socket 库 ,需要1. 初始化动态库  2. 引用lib库
            WSADATA ws;
            WSAStartup(MAKEWORD(2, 2), &ws);//也加载动态库,引用加1
        #endif
        int sock=socket(AF_INET,SOCK_STREAM,0);//确定用什么协议,用tcp ip 小于0代表失败
        if(sock<0)
        {
            cout<<"连接失败"<<endl;
            return -1;
        }
    
        sockaddr_in saddr; //存取ip地址,port
        saddr.sin_family=AF_INET; //tcp/ip协议
        saddr.sin_port=htons(port); // 统一转化为大端存储(网络默认)
        saddr.sin_addr.s_addr=htonl(0);//一个机器可能有多个ip,这里默认任意ip都可以接受
        
        // socket 和 端口ip等信息绑定
        if(bind(sock,(sockaddr*)&saddr,sizeof(saddr))!=0)
        {
            cout<<"绑定失败"<<endl;
            return -2;
        }
    
        cout<<"绑定成功"<<endl;
    
        //开始监听
        listen(sock,10);
    
        // int client_sock=accept(sock,0,0); //0代表不想知道对方的连接信息 
        // // 会返回一个新的socket,与这个用户单独进行通信的,每一个连接都会生成一个socket
        // cout<<"client sock"<
    
        for(;;)
        {
            // 获取 连接客户端的ip和端口号
            sockaddr_in caddr;
            socklen_t len=0;
            int client_sock=accept(sock,(sockaddr*)&caddr,&len);
            if(client_sock<=0)
            {
                break;
            }
            cout<<"client sock"<<client_sock<<endl;
            string ip=inet_ntoa(caddr.sin_addr);
            cout<<"client ip:"<<ip<<endl;
            unsigned short cport=ntohs(caddr.sin_port);//把网络上转换成本地的,linux其实不需要
            cout<<"client port:"<<cport<<endl;
            // 创建一个线程
            TcpThread* thr=new TcpThread(client_sock);
            thread sth(&TcpThread::Main,thr);
            sth.detach();//拆分,释放主线程所拥有子线程的资源
    
        }
        close(sock);
    
        //需要传client_sock,
       
        std::cout << "Hello World!\n";
        std::cout << "Hello World!\n";
        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
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146

    Makefile

    socket_t:socket_test.cpp
    	g++ socket_test.cpp -std=c++11 -lpthread -o socket_t 
    
    • 1
    • 2

    一个shell 开启服务

    make
    ./socket_t
    
    • 1
    • 2

    另一个 进行连接

    telnet 10.112.146.228 8080
    
    • 1

    另一个再进行连接

    telnet 10.112.146.228 8080
    
    • 1
  • 相关阅读:
    react实现数据进度条展示组件
    手写Java设计模式之抽象工厂模式,附源码解读
    C++ Qt/Eigen拟合三维平面与三维圆
    关于 Spring Boot 自动装配你知道多少?
    Ubuntu 20.04源码安装sysbench 1.0.20,源码安装sysstat v12.7.2
    怎么将电脑excel文档内的数据转换为图片形式
    微信小程序学习笔记3.0
    PAM从入门到精通(二十四)
    软件工程,必须跨越的四大门槛
    vue的常用指令
  • 原文地址:https://blog.csdn.net/hch977/article/details/127853451