小白一步一步学并发编程(4)—— tcp多线程并发

多线程并发的逻辑和多进程类似,这里只不过是将线程代替了进程,多线程的好处是共享进程的内存空间,节省资源。这里主线程处理连接请求,通过新建线程来处理连接建立后的数据交互和处理。

tcp_server_thread.h

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <thread>
#include <pthread.h>
#include <string>
#include <mutex>
#include "tcp_server.h"
                
                
//using namespace std;

#define MAXLINE 4096

class ThreadServer : public Server{
        public:
                ThreadServer(string ip, int port):Server(ip, port){
                }       
                static void *threadWorker(void *args);
                int start();
};

tcp_server_thread.cpp

#include <iostream>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <thread>
#include <pthread.h>
#include <string>
#include <mutex>
#include <sys/wait.h>
#include "tcp_server_thread.h"

void *ThreadServer::threadWorker(void * args){
        char buff[MAXLINE];
        int connfd = long(args);
        while(true){
                //int n = recv(connfd,buff,MAXLINE,MSG_DONTWAIT);
                int n = recv(connfd,buff,MAXLINE,0);
                if(n>0){
                        buff[n] = '\0';
                        m_log->outputLog("thread:%lu,connfd:%d,recv msg:%s",pthread_self(),connfd,buff);
                }else{
                        if(errno == EINTR && errno == EAGAIN){
                                m_log->outputLog("recv error: %s, errno:%d",strerror(errno),errno);
                                continue;
                        }else{
                                m_log->outputLog("recv error: %s, errno:%d",strerror(errno),errno);
                                break;
                        }
                }
        }
        close(connfd);
        return NULL;
}

int ThreadServer::start(){
        int sockfd,connfd;
        struct sockaddr_in cliaddr;
        socklen_t clilen;
        if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
                m_log->outputLog("socket create failed: error %s, errno:%d",strerror(errno),errno);
                return 0;
        }
        m_log->outputLog("socket create %d", sockfd);
        int ret = ::bind(sockfd, (struct sockaddr*) &addr, sizeof(addr));
        if(ret == -1){
                m_log->outputLog("bind socket error: %s, errno:%d",strerror(errno),errno);
                return 0;
        }
        if((listen(sockfd,10)) == -1){
                m_log->outputLog("listen error: %s, errno:%d",strerror(errno),errno);
                return 0;
        }
        //socklen_t len = sizeof(cliaddr);

        while(true){
                socklen_t len = sizeof(cliaddr);
                if((connfd = accept(sockfd,(struct sockaddr*)&cliaddr,&len)) == -1){
                        m_log->outputLog("accept error: %s, errno:%d",strerror(errno),errno);
                        continue;
                }
                pthread_t threadworker;
                
                if(pthread_create(&threadworker,NULL,threadWorker,(void*)connfd) != 0){
                        m_log->outputLog("fork error:%s, error:%d", strerror(errno),errno);
                }       
        }       
        close(sockfd);
} 

test_server.cpp

#include "logger.h"
#include "tcp_server.h"
#include "tcp_server_thread.h"
#include "tcp_server_process.h"
#include "tcp_server_epoll.h"
#include "tcp_server_libevent.h"
#include "tcp_server_threadpoolevent.h"
#include <signal.h>
#include <sys/wait.h>

int main(){
        //logger *m_log = logger::get_instance();
        m_log->openLogFile("./","test_server.log",true);

        //Server *m_server = new Server("111.206.73.111",12345);
        Server *m_server = new ThreadServer("111.206.73.111",12345);
        //Server *m_server = new ProcessServer("111.206.73.111",12345);
        //Server *m_server = new EpollServer("111.206.73.111",12345);
        //Server *m_server = new poolEventServer("111.206.73.111",12345);
        m_server->init(m_log);
        m_server->start();
}

这里需要说明的一点是,在C++的中,普通成员函数不能直接作为pthread_create的线程函数,只能声明为静态函数,而类中的静态函数是无法知己访问类成员的,因为静态函数不会传递类this指针作为参数。因此,这里的ThreadServer::threadWorker声明为类静态成员函数。C++11在这方面做了改进,引进了Thread类,通过Thread类绑定任务函数,这里的函数可以是普通成员函数,有兴趣的可以进一步探究。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值