基于多反应堆的高并发服务器【C/C++/Reactor】(中)创建并初始化TcpServer实例

发布时间:2024年01月05日

对于一个TcpServer来说,它的灵魂是什么?就是需要提供一个事件循环EventLop(EventLoop),不停地去检测有没有客户端的连接到达,有没有客户端给服务器发送数据,描述的这些动作,反应堆模型能够胜任。当服务器和客户端建立连接之后,剩下的就是网络通信,在通信的时候,需要把接收的数据和要发送的数据存储到一块内存里边,Buffer(Buffer)就是为此量身定制的。另外,如果服务器想和客户端实现并发操作,需要用到多线程。我们提供了线程池ThreadPool(ThreadPool),剩下的事就是把服务器模型里边的代码实现一下,基于服务器的整体流程实现一下TcpConnection

这个TcpConnection就是服务器和客户端建立连接之后,它们是在通信的时候,其实就需要用到Http,如果想要实现一个HttpServer,就需要用到Http协议,再把HttpRequestHttpResponse写出来之后,整个项目的流程就全部走通了。

TcpServer分为几个部分:

  1. 主线程需要有一个Listener(包括端口port,监听的文件描述符listenFd
  2. 主线程的事件循环MainEventLoop(反应堆)
  3. 一个线程池ThreadPool
  4. TcpConnection其实是子线程的任务。服务器与客户端建立连接之后,子线程要是想工作的话,就必须创建一个TcpConnection实例。如果没有这个TcpConnection模块,子线程就不知道在建立连接之后需要做什么事情
struct Listener {
    int lfd;
    unsigned short port;
};

struct TcpServer {
    struct Listener* listener; // 监听套接字
    struct EventLoop* mainLoop; // 主线程的事件循环(反应堆模型)
    struct ThreadPool* threadPool; // 线程池
    int threadNum; // 线程数量
};

一、创建并初始化TcpServer实例

(1)初始化监听

// 初始化监听
struct Listener* listenerInit(unsigned short port);
// 初始化监听
struct Listener* listenerInit(unsigned short port) {
    // 创建一个Listner实例 -> listener
    struct Listener* listener = (struct Listener*)malloc(sizeof(struct Listener));
    // 1.创建一个监听的文件描述符 -> lfd
    int lfd = socket(AF_INET,SOCK_STREAM,0); // AF_INET -> (网络层协议:Ipv4) ;SOCK_STREAM -> (传输层协议:流式协议)  ;0 -> :表示使用Tcp
    if(lfd == -1) {
        perror("socket");              
        return -1;
    }   
    // 2.设置端口复用
    int opt = 1;
    int ret =  setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)); 
    if(ret == -1) {
        perror("setsockopt");
        return -1;
    }
    // 3.绑定
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);// 主机字节序(小端)转成网络字节序(大端) 端口的最大数量:2^16=65536
    addr.sin_addr.s_addr = INADDR_ANY;// 0.0.0.0 
    ret = bind(lfd,(struct sockaddr*)&addr,sizeof(addr));
    if(ret == -1) {
        perror("bind");
        return -1;
    }
    // 4.设置监听
    ret = listen(lfd,128);
    if(ret == -1) {
        perror("listen");
        return -1;
    }
    listener->lfd = lfd;
    listener->port = port;
    return listener;
}

(2)创建并初始化TcpServer实例

TcpServer结构与工作原理?

(一)服务器结构

  1. Listener: 监听特定端口,等待客户端的连接请求。主要包括端口和监听的文件描述符
  2. MainEventLoop主线程事件循环(主线程反应堆): 负责接收和处理来自客户端的请求
  3. ThreadPool线程池: 用于处理并发连接每个新连接都会有一个子线程处理
  4. TcpConnection: 每个客户端连接都会有一个对应的TcpConnection实例,用于处理该连接的通信

(二)初始化步骤

(1)创建服务器实例:申请TcpServer结构体的内存空间

(2)初始化Listener:

  • 指定服务器要绑定的本地端口(unsigned short类型)
  • 初始化监听的文件描述符

(3)初始化MainEventLoop主线程的事件循环或反应堆

(4)ThreadPool线程池初始化:根据需要的子线程数量(threadNum)初始化线程池

(5)返回值: 返回初始化完成的TcpServer的地址给调用者

// 初始化
struct TcpServer* tcpServerInit(unsigned short port,int threadNum);
// 初始化
struct TcpServer* tcpServerInit(unsigned short port,int threadNum) {
    struct TcpServer* tcp = (struct TcpServer*)malloc(sizeof(struct TcpServer));
    tcp->listener = listenerInit(port); // 创建listener
    tcp->mainLoop = eventLoopInit(); // 主线程的事件循环(反应堆模型)
    tcp->threadPool = threadPoolInit(tcp->mainLoop,threadNum); // 创建线程池
    tcp->threadNum = threadNum; // 线程数量
    return tcp;
}

文章来源:https://blog.csdn.net/weixin_41987016/article/details/135407893
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。