网络编程套接字(四)

网络编程套接字(四)

一、实现tcp服务器多用户版本(多进程、多线程、线程池版本)

  • tcp_process_server.hpp
#pragma once
#include "tcp_socket.hpp"
#include <functional>
#include <signal.h>

typedef std::function<void (const std::string& req,std::string* resp)> Handler;

class TcpProcessServer
{
  public:
    TcpProcessServer(const std::string& ip,uint16_t port)
      :ip_(ip)
       ,port_(port)
  {
    //对于多进程版本服务器,在请求到来时生成子进程处理请求,父进程继续accept。如果父进程不等待
    //子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。如果父进程等待子进程结束
    //将增加父进程的负担,影响服务器进程的并发性能。在Linux下可以简单地将 SIGCHLD信号的操作设为SIG_IGN。
    //将SIGCHLD(子进程结束自动像父进程发送的信号)此信号设为忽略SIG_IGN
    signal(SIGCHLD,SIG_IGN);
  }

    void ProcessConnect(TcpSocket& new_sock,const std::string& ip,uint16_t port,Handler handler)
    {
      int ret = fork();
      if(ret > 0)
      {
        //father
        //父进程不需要做额外操作,只需要循环accept即可,就直接返回
        //此处如果采用wait操作,那么就达不到采用多进程的目的,采用多进程为了可以同时处理多个用户
        //如果在此处wait,那么父进程就会等待子进程处理客户端请求结束,特别耗费时间
        new_sock.Close();
        return;
      }
      else if(ret == 0)
      {
        //child
        //处理具体的链接过程即根据请求计算响应
        while(1)
        {
          std::string req;
          bool ret = new_sock.Recv(&req);
          if(!ret)
          {
            printf("[client %s : %d] disconnect!\n",ip.c_str(),port);
            exit(0);
          }

          std::string resp;
          handler(req,&resp);

          new_sock.Send(resp);

          printf("[client %s : %d ] req : %s, resp : %s\n",ip.c_str(),port,req.c_str(),resp.c_str());

        }
      }
      else
      {
        perror("fork is error");

      }
    }

    bool Start(Handler handler)
    {
      //1. 创建 socket;
      CHECK_RET(listen_sock_.Socket());

      // 2. 绑定端口号
      CHECK_RET(listen_sock_.Bind(ip_, port_));

      // 3. 进行监听
      CHECK_RET(listen_sock_.Listen(5));

      // 4. 进入事件循环
      for (;;) 
      {
        // 5. 进行 accept
        TcpSocket new_sock;
        std::string ip;
        uint16_t port = 0;
        if (!listen_sock_.Accept(&new_sock, &ip, &port)) 
        {
          continue;
        }

        printf("[client %s:%d] connect!\n", ip.c_str(), port);
        ProcessConnect(new_sock, ip, port, handler);
      }
      return true;
    }
  private:
    TcpSocket listen_sock_;
    std::string ip_;
    uint16_t port_;
};

  • tcp_pthread_server.hpp
#pragma once
#include <functional>
#include <pthread.h>
#include "tcp_socket.hpp"

typedef std::function<void (const std::string& req, std::string* resp)> Handler;

struct ThreadArg 
{
  TcpSocket new_sock;
  std::string ip;
  uint16_t port;
  Handler handler;
};

class TcpThreadServer 
{
  public:
    TcpThreadServer(const std::string& ip, uint16_t port) 
      : ip_(ip), port_(port) 
    {

    } 

    bool Start(Handler handler) 
    {
      // 1. 创建 socket;
      CHECK_RET(listen_sock_.Socket());

      // // 2. 绑定端口号
      CHECK_RET(listen_sock_.Bind(ip_, port_));

      // // 3. 进行监听
      CHECK_RET(listen_sock_.Listen(5));

      // 4. 进入循环
      for (;;) 
      {
        // 5. 进行 accept
        ThreadArg* arg = new ThreadArg();
        arg->handler = handler;

        bool ret = listen_sock_.Accept(&arg->new_sock, &arg->ip, &arg->port);
        if (!ret) 
        {
          continue;
        }

        printf("[client %s:%d] connect\n", arg->ip.c_str(), arg->port);

        // 6. 创建新的线程完成具体操作
        pthread_t tid;
        pthread_create(&tid, NULL, ThreadEntry, arg);
        pthread_detach(tid);
      }
      return true;
    }

    static void* ThreadEntry(void* arg) 
    {
      ThreadArg* p = reinterpret_cast<ThreadArg*>(arg);
      PthreadConnect(p);
      // 一定要记得释放内存!!! 也要记得关闭文件描述符
      p->new_sock.Close();
      delete p;
      return NULL;
    }

    static void PthreadConnect(ThreadArg* arg) 
    {
      // 1. 循环进行读写
      for (;;) 
      {
        std::string req;

        // 2. 读取请求
        bool ret = arg->new_sock.Recv(&req);
        if (!ret) 
        {
          printf("[client %s:%d] disconnected!\n", arg->ip.c_str(), arg->port);
          break;
        }

        std::string resp;
        // 3. 根据请求计算响应
        arg->handler(req, &resp);

        // 4. 发送响应
        arg->new_sock.Send(resp);
        printf("[client %s:%d] req: %s, resp: %s\n", arg->ip.c_str(),
            arg->port, req.c_str(), resp.c_str());
      }
    }

  private:
    TcpSocket listen_sock_;
    std::string ip_;
    uint16_t port_;
};

  • tcp_threadpool_server.hpp
#pragma once
#include"tcp_socket.hpp"
#include<pthread.h>
#include"threadpool.hpp"
#include<sys/syscall.h>
#include<unistd.h>
#include<stdio.h>
#include <functional>

typedef std::function<void (const std::string& req,std::string* resp)> Handler;

struct Arg
{
  TcpSocket sock_;
  std::string _ip;
  uint16_t _port;
  Handler _handler;
};

class MyTask:public Task
{
  public:
    MyTask(void* arg)
      :arg_(arg)
    {}

    virtual void Run()override
    {
      Arg *arg = (Arg*)arg_;
      TcpSocket newsock_ = arg->sock_;
      std::string ArgIp = arg->_ip;
      int ArgPort = arg->_port;
      Handler ArgHandler = arg->_handler;

      while(1)
      {
        std::string msg;
        int n = newsock_.Recv(&msg);
        if(n < 0)
        {
          continue;

        }
        else if(n == 0)
        {
          printf("[%s:%d]客户端已经关闭!\n",ArgIp.c_str(),ArgPort);
          break;

        }

        printf("[%s:%d]客户端输入:%s\n",ArgIp.c_str(),ArgPort,msg.c_str());

        std::string resp;
        ArgHandler(msg,&resp);

        if(newsock_.Send(resp) == false)
          continue;
      }
      newsock_.Close();
      delete arg;
    }

  private:
    void* arg_;
};


class TcpThreadPoolServer
{
  public:
    TcpThreadPoolServer(const std::string ip,uint16_t port)
      :pool(10)
       ,ip_(ip)
       ,port_(port)
    {}

    ~TcpThreadPoolServer()
    {
      sock_.Close();

    }

    bool Start(Handler handler)
    {
      if(sock_.Socket() == false)
        return false;
      
      cout<<__LINE__<<endl;
      if(sock_.Bind(ip_,port_) == false)
        return false;
      cout<<__LINE__<<endl;

      if(sock_.Listen() == false)
        return false;

      while(1)
      {
        Arg *NewArg = new Arg;
        NewArg->_handler = handler;
        if(sock_.Accept(&(NewArg->sock_),&NewArg->_ip,&NewArg->_port) == false)
          continue;

        printf("[%s:%d]客户端已连接!\n",NewArg->_ip.c_str(),NewArg->_port);
        pool.AddTask(new MyTask((void*)NewArg));
      }
    }

  private:
    TcpSocket sock_;
    ThreadPool pool;
    std::string ip_;
    uint16_t port_;
};


发布了71 篇原创文章 · 获赞 29 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/wolfGuiDao/article/details/104270095