基于C/C++在Linux上的极简线程池&tcpsocket通信Demo

打开方式:

在Linux上(同一台设备同时运行多台客户端和服务器也行,或者同一局域网下的设备),选一台设备编译运行服务器(serve.cpp(创建一个把代码丢进去)),记得链接lpthread

在终端里

编译 : g++ ./serve.cpp -lpthread

运行:./a.out

在另(一/多)台设备编译运行客户端即可

编译 : g++ ./client.cpp -lpthread

运行:./a.out

源码

客户端:

#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<arpa/inet.h>
#include<unistd.h>
using namespace std;

int main()
{
    
    int fd = socket(AF_INET,SOCK_STREAM,0);
    if(fd == -1)
    {
        perror("socket is failed to initialize!");
        return -1;
    }
    
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(9999);//端口同服务器中的9999
    inet_pton(AF_INET,"192.168.46.128",&saddr.sin_addr.s_addr);//在服务器运行的linux终端ipconfig获取服务器当前ip填入
    int ret = connect(fd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(ret == -1)
    {
        perror("connect Error!");
        return -1;
    }

    int number = 0;
    while(1)
    {
        char buf[1024];
        sprintf(buf,"hello,world,%d...\n",number++);
        send(fd,buf,strlen(buf)+1,0);

        memset(buf,0,sizeof(buf));
        int len = recv(fd,buf,sizeof(buf),0);
        if(len>0)
        {
            cout<<"ServeSay:"<<buf<<endl;
        }
        else if(len == 0)
        {
            cout<<"Serve is out of line"<<endl;
            break;
        }
        else
        {
            perror("receive Error");
            break;
        }
        sleep(1);
    }
    close(fd);
    return 0;
}
 

服务器:

#include<iostream>
#include<string>
#include<stdio.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<thread>
#include<vector>
#include<queue>
#include<mutex>
#include<functional>
#include<condition_variable>

using namespace std;

//线程池

class ThreadPool
{
    public:
        ThreadPool(int ThreadNum):stop(false)
        {
            V_threads.emplace_back([this]{
                while(true)
                {
                    unique_lock<mutex> u_lock(mtx);
                    cv.wait(u_lock,[this]{
                        return stop || !tasks.empty();
                    });//没任务线程就睡觉等
                    if(stop&&tasks.empty())
                    return;
                    function<void()> task(move(tasks.front()));//把队列中第一个任务内容转交给task留下空壳
                    tasks.pop();//已经被task取走任务队列中第一个空白任务弹出销毁
                    u_lock.unlock();
                    task();//就是后面传进去的working和参数
                }

            });
        }

        ~ThreadPool()
        {
            {
                unique_lock<mutex> u_lock(mtx);//新建作用域({})把stop锁住
                stop = true;
            }
            cv.notify_all();//唤醒所有线程检查有无任务未完成
            for(auto &t : V_threads)
            {
                t.join();//遍历线程池,等待所有线程结束
            }
        }

template<class F,class ...Args>
void enqueue(F&& f,Args && ...args)//定义线程池自用函数enqueue接受任何函数和任何类型数量的参数
{
    function<void()> task = bind(std::forward<F>(f), forward<Args>(args)...);
    {
        unique_lock<mutex> u_lock(mtx);
        tasks.emplace(move(task));//把enqueue接收到的任务加到线程池里
    }
    cv.notify_one();//随机唤醒一个沉睡线程
}


private:
    bool stop;
    vector<thread> V_threads;
    queue<function<void()>> tasks;
    condition_variable cv;
    mutex mtx;
};

//和客户端建立连接后收发

void* working(int cfd,struct sockaddr_in caddr,socklen_t addrlen)
{
    char ip[32];
    printf("ClientIP:%s,Port:%d\n",
    inet_ntop(AF_INET,&caddr.sin_addr.s_addr,ip,sizeof(ip)),
    ntohs(caddr.sin_port));
    

    while(1)
    {
        char buf[1024];
        int len = recv(cfd,buf,sizeof(buf),0);
        if(len>0)
        {
            cout<<"ClientSay:"<<buf<<endl;
            send(cfd,buf,len,0);
        }
        else if(len == 0)
        {
            cout<<"Client is out of line"<<endl;
            break;
        }
        else
        {
            perror("receive Error");
            break;
        }
        
    }
}

int main()
{
    
    int fd = socket(AF_INET,SOCK_STREAM,0);//创建一个名为fd的套接字(ipv4,流式传输,0)
    if(fd == -1)
    {
        perror("socket is failed to initialize!");//print error
        return -1;
    }
    
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;//ipv4
    saddr.sin_port = htons(9999);//9999端口号从host转成net
    saddr.sin_addr.s_addr = INADDR_ANY;//获取本地ip
    int ret = bind(fd,(struct sockaddr*)&saddr,sizeof(saddr));//把sockaddr_in类型强转为sockaddr后和监听套接字进行绑定
    if(ret == -1)
    {
        perror("bind is failed to initialize!");
        return -1;
    }
    
    ret = listen(fd,128);//开始监听fd套接字,最大队列128,监听返回值丢给ret
    if(ret == -1)
    {
        perror("listen if failed to initialize!");
        return -1;
    }
    
    struct sockaddr_in caddr;//客户端地址结构体创建(里面啥也没有)
    socklen_t addrlen = sizeof(caddr);
    
    ThreadPool pool(4);//创建一个包含4个线程的线程池

    while(1)
    {
        int cfd = accept(fd,(struct sockaddr*)&caddr,&addrlen);//把客户端地址结构体传入,如果接到了客户端的通信请求会把客户端的ip和端口放进caddr里
        if(cfd == -1)
        {
            perror("accept error");
            return -1;
        }
        pool.enqueue(working,cfd,caddr,addrlen);//把working(收发信息)丢给线程池处理
    }


    close(fd);
return 0;
}
 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值