当前位置:   article > 正文

仿Muduo库实现高并发服务器——Acceptor模块

仿Muduo库实现高并发服务器——Acceptor模块

        Acceptor模块是为了创建套接字,并且接收新到来的客户端套接字,将对应套接字的Channel对象添加到Poller对象中,进行事件监控。

Acceptor模块成员函数:

连接回调函数:

 在构造函数这里,就对主线程上面的网络套接字进行回调函数的设置。

 

 会在TcpServer模块中,启动该套接字读事件监控,并将对应的Channel对象添加到Poller对象中。

服务端网络套接字的创建:

 

        由上面代码可以看出,服务器端网络套接字的创建,就是对服务端指定的端口进行监听,这个地址是不能固定的,因为一个端口有可能有几个网卡,服务器不知道要监听那个网卡。于是,服务端一般就是,任意地址,让服务器监听这个端口上的所有网卡。

Socket模块整体代码:

  1. #define MAX_LISTEN 1024
  2. class Socket {
  3. private:
  4. int _sockfd;
  5. public:
  6. Socket():_sockfd(-1) {}
  7. Socket(int fd): _sockfd(fd) {}
  8. ~Socket() { Close(); }
  9. int Fd() { return _sockfd; }
  10. //创建套接字
  11. bool Create() {
  12. // int socket(int domain, int type, int protocol)
  13. _sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  14. if (_sockfd < 0) {
  15. ERR_LOG("CREATE SOCKET FAILED!!");
  16. return false;
  17. }
  18. return true;
  19. }
  20. //绑定地址信息
  21. bool Bind(const std::string &ip, uint16_t port) {
  22. struct sockaddr_in addr;
  23. addr.sin_family = AF_INET;
  24. addr.sin_port = htons(port);
  25. addr.sin_addr.s_addr = inet_addr(ip.c_str());
  26. socklen_t len = sizeof(struct sockaddr_in);
  27. // int bind(int sockfd, struct sockaddr*addr, socklen_t len);
  28. int ret = bind(_sockfd, (struct sockaddr*)&addr, len);
  29. if (ret < 0) {
  30. ERR_LOG("BIND ADDRESS FAILED!");
  31. return false;
  32. }
  33. return true;
  34. }
  35. //开始监听
  36. bool Listen(int backlog = MAX_LISTEN) {
  37. // int listen(int backlog)
  38. int ret = listen(_sockfd, backlog);
  39. if (ret < 0) {
  40. ERR_LOG("SOCKET LISTEN FAILED!");
  41. return false;
  42. }
  43. return true;
  44. }
  45. //向服务器发起连接
  46. bool Connect(const std::string &ip, uint16_t port) {
  47. struct sockaddr_in addr;
  48. addr.sin_family = AF_INET;
  49. addr.sin_port = htons(port);
  50. addr.sin_addr.s_addr = inet_addr(ip.c_str());
  51. socklen_t len = sizeof(struct sockaddr_in);
  52. // int connect(int sockfd, struct sockaddr*addr, socklen_t len);
  53. int ret = connect(_sockfd, (struct sockaddr*)&addr, len);
  54. if (ret < 0) {
  55. ERR_LOG("CONNECT SERVER FAILED!");
  56. return false;
  57. }
  58. return true;
  59. }
  60. //获取新连接
  61. int Accept() {
  62. // int accept(int sockfd, struct sockaddr *addr, socklen_t *len);
  63. int newfd = accept(_sockfd, NULL, NULL);
  64. if (newfd < 0) {
  65. ERR_LOG("SOCKET ACCEPT FAILED!");
  66. return -1;
  67. }
  68. return newfd;
  69. }
  70. //接收数据
  71. ssize_t Recv(void *buf, size_t len, int flag = 0) {
  72. // ssize_t recv(int sockfd, void *buf, size_t len, int flag);
  73. ssize_t ret = recv(_sockfd, buf, len, flag);
  74. if (ret <= 0) {
  75. //EAGAIN 当前socket的接收缓冲区中没有数据了,在非阻塞的情况下才会有这个错误
  76. //EINTR 表示当前socket的阻塞等待,被信号打断了,
  77. if (errno == EAGAIN || errno == EINTR) {
  78. return 0;//表示这次接收没有接收到数据
  79. }
  80. ERR_LOG("SOCKET RECV FAILED!!");
  81. return -1;
  82. }
  83. return ret; //实际接收的数据长度
  84. }
  85. ssize_t NonBlockRecv(void *buf, size_t len) {
  86. return Recv(buf, len, MSG_DONTWAIT); // MSG_DONTWAIT 表示当前接收为非阻塞。
  87. }
  88. //发送数据
  89. ssize_t Send(const void *buf, size_t len, int flag = 0) {
  90. // ssize_t send(int sockfd, void *data, size_t len, int flag);
  91. ssize_t ret = send(_sockfd, buf, len, flag);
  92. if (ret < 0) {
  93. if (errno == EAGAIN || errno == EINTR) {
  94. return 0;
  95. }
  96. ERR_LOG("SOCKET SEND FAILED!!");
  97. return -1;
  98. }
  99. return ret;//实际发送的数据长度
  100. }
  101. ssize_t NonBlockSend(void *buf, size_t len) {
  102. if (len == 0) return 0;
  103. return Send(buf, len, MSG_DONTWAIT); // MSG_DONTWAIT 表示当前发送为非阻塞。
  104. }
  105. //关闭套接字
  106. void Close() {
  107. if (_sockfd != -1) {
  108. close(_sockfd);
  109. _sockfd = -1;
  110. }
  111. }
  112. //创建一个服务端连接
  113. bool CreateServer(uint16_t port, const std::string &ip = "0.0.0.0", bool block_flag = false) {
  114. //1. 创建套接字,2. 绑定地址,3. 开始监听,4. 设置非阻塞, 5. 启动地址重用
  115. if (Create() == false) return false;
  116. if (block_flag) NonBlock();
  117. if (Bind(ip, port) == false) return false;
  118. if (Listen() == false) return false;
  119. ReuseAddress();
  120. return true;
  121. }
  122. //创建一个客户端连接
  123. bool CreateClient(uint16_t port, const std::string &ip) {
  124. //1. 创建套接字,2.指向连接服务器
  125. if (Create() == false) return false;
  126. if (Connect(ip, port) == false) return false;
  127. return true;
  128. }
  129. //设置套接字选项---开启地址端口重用
  130. void ReuseAddress() {
  131. // int setsockopt(int fd, int leve, int optname, void *val, int vallen)
  132. int val = 1;
  133. setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, (void*)&val, sizeof(int));
  134. val = 1;
  135. setsockopt(_sockfd, SOL_SOCKET, SO_REUSEPORT, (void*)&val, sizeof(int));
  136. }
  137. //设置套接字阻塞属性-- 设置为非阻塞
  138. void NonBlock() {
  139. //int fcntl(int fd, int cmd, ... /* arg */ );
  140. int flag = fcntl(_sockfd, F_GETFL, 0);
  141. fcntl(_sockfd, F_SETFL, flag | O_NONBLOCK);
  142. }
  143. };

Acceptor模块整体代码:

  1. class Acceptor {
  2. private:
  3. Socket _socket;//用于创建监听套接字
  4. EventLoop *_loop; //用于对监听套接字进行事件监控
  5. Channel _channel; //用于对监听套接字进行事件管理
  6. using AcceptCallback = std::function<void(int)>;
  7. AcceptCallback _accept_callback;
  8. private:
  9. /*监听套接字的读事件回调处理函数---获取新连接,调用_accept_callback函数进行新连接处理*/
  10. void HandleRead() {
  11. int newfd = _socket.Accept();
  12. if (newfd < 0) {
  13. return ;
  14. }
  15. if (_accept_callback) _accept_callback(newfd);
  16. }
  17. int CreateServer(int port) {
  18. bool ret = _socket.CreateServer(port);
  19. assert(ret == true);
  20. return _socket.Fd();
  21. }
  22. public:
  23. /*不能将启动读事件监控,放到构造函数中,必须在设置回调函数后,再去启动*/
  24. /*否则有可能造成启动监控后,立即有事件,处理的时候,回调函数还没设置:新连接得不到处理,且资源泄漏*/
  25. Acceptor(EventLoop *loop, int port): _socket(CreateServer(port)), _loop(loop),
  26. _channel(loop, _socket.Fd()) {
  27. _channel.SetReadCallback(std::bind(&Acceptor::HandleRead, this));
  28. }
  29. void SetAcceptCallback(const AcceptCallback &cb) { _accept_callback = cb; }
  30. void Listen() { _channel.EnableRead(); }
  31. };

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/1021025
推荐阅读
相关标签
  

闽ICP备14008679号