<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ## 7) tcp_server端集成tcp_conn鏈接屬性 ? 現在我們已經把server端所創建的套接字包裝成了tcp_conn類,那么我們就可以對他們進行一定的管理,比如限制最大的連接數量等等。 ### 7.1 定義鏈接管理相關屬性 > lars_reactor/include/tcp_server.h ```c #pragma once #include <netinet/in.h> #include "event_loop.h" #include "tcp_conn.h" class tcp_server { public: //server的構造函數 tcp_server(event_loop* loop, const char *ip, uint16_t port); //開始提供創建鏈接服務 void do_accept(); //鏈接對象釋放的析構 ~tcp_server(); private: //基礎信息 int _sockfd; //套接字 struct sockaddr_in _connaddr; //客戶端鏈接地址 socklen_t _addrlen; //客戶端鏈接地址長度 //event_loop epoll事件機制 event_loop* _loop; //---- 客戶端鏈接管理部分----- public: static void increase_conn(int connfd, tcp_conn *conn); //新增一個新建的連接 static void decrease_conn(int connfd); //減少一個斷開的連接 static void get_conn_num(int *curr_conn); //得到當前鏈接的刻度 static tcp_conn **conns; //全部已經在線的連接信息 private: //TODO //從配置文件中讀取 #define MAX_CONNS 2 static int _max_conns; //最大client鏈接個數 static int _curr_conns; //當前鏈接刻度 static pthread_mutex_t _conns_mutex; //保護_curr_conns刻度修改的鎖 }; ``` 這里解釋一下關鍵成員 - `conns`:這個是記錄已經建立成功的全部鏈接的struct tcp_conn*數組。 - `_curr_conns`:表示當前鏈接個數,其中`increase_conn,decrease_conn,get_conn_num`三個方法分別是對鏈接個數增加、減少、和獲取。 - `_max_conns`:限制的最大鏈接數量。 - `_conns_mutex`:保護_curr_conns的鎖。 ? 好了,我們首先首先將這些靜態變量初始化,并且對函數見一些定義: > lars_reactor/src/tcp_server.cpp ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include <unistd.h> #include <signal.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <arpa/inet.h> #include <errno.h> #include "tcp_server.h" #include "tcp_conn.h" #include "reactor_buf.h" // ==== 鏈接資源管理 ==== //全部已經在線的連接信息 tcp_conn ** tcp_server::conns = NULL; //最大容量鏈接個數; int tcp_server::_max_conns = 0; //當前鏈接刻度 int tcp_server::_curr_conns = 0; //保護_curr_conns刻度修改的鎖 pthread_mutex_t tcp_server::_conns_mutex = PTHREAD_MUTEX_INITIALIZER; //新增一個新建的連接 void tcp_server::increase_conn(int connfd, tcp_conn *conn) { pthread_mutex_lock(&_conns_mutex); conns[connfd] = conn; _curr_conns++; pthread_mutex_unlock(&_conns_mutex); } //減少一個斷開的連接 void tcp_server::decrease_conn(int connfd) { pthread_mutex_lock(&_conns_mutex); conns[connfd] = NULL; _curr_conns--; pthread_mutex_unlock(&_conns_mutex); } //得到當前鏈接的刻度 void tcp_server::get_conn_num(int *curr_conn) { pthread_mutex_lock(&_conns_mutex); *curr_conn = _curr_conns; pthread_mutex_unlock(&_conns_mutex); } //... //... //... ``` ### 7.2 創建鏈接集合初始化 ? 我們在初始化tcp_server的同時也將`conns`初始化. > lars_reactor/src/tcp_server.cpp ```c //server的構造函數 tcp_server::tcp_server(event_loop *loop, const char *ip, uint16_t port) { bzero(&_connaddr, sizeof(_connaddr)); //忽略一些信號 SIGHUP, SIGPIPE //SIGPIPE:如果客戶端關閉,服務端再次write就會產生 //SIGHUP:如果terminal關閉,會給當前進程發送該信號 if (signal(SIGHUP, SIG_IGN) == SIG_ERR) { fprintf(stderr, "signal ignore SIGHUP\n"); } if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { fprintf(stderr, "signal ignore SIGPIPE\n"); } //1. 創建socket _sockfd = socket(AF_INET, SOCK_STREAM /*| SOCK_NONBLOCK*/ | SOCK_CLOEXEC, IPPROTO_TCP); if (_sockfd == -1) { fprintf(stderr, "tcp_server::socket()\n"); exit(1); } //2 初始化地址 struct sockaddr_in server_addr; bzero(&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; inet_aton(ip, &server_addr.sin_addr); server_addr.sin_port = htons(port); //2-1可以多次監聽,設置REUSE屬性 int op = 1; if (setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, &op, sizeof(op)) < 0) { fprintf(stderr, "setsocketopt SO_REUSEADDR\n"); } //3 綁定端口 if (bind(_sockfd, (const struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { fprintf(stderr, "bind error\n"); exit(1); } //4 監聽ip端口 if (listen(_sockfd, 500) == -1) { fprintf(stderr, "listen error\n"); exit(1); } //5 將_sockfd添加到event_loop中 _loop = loop; //6 ============= 創建鏈接管理 =============== _max_conns = MAX_CONNS; //創建鏈接信息數組 conns = new tcp_conn*[_max_conns+3];//3是因為stdin,stdout,stderr 已經被占用,再新開fd一定是從3開始,所以不加3就會棧溢出 if (conns == NULL) { fprintf(stderr, "new conns[%d] error\n", _max_conns); exit(1); } //=========================================== //7 注冊_socket讀事件-->accept處理 _loop->add_io_event(_sockfd, accept_callback, EPOLLIN, this); } ``` ? 這里有一段代碼: ```c conns = new tcp_conn*[_max_conns+3]; ``` ? 其中3是因為我們已經默認打開的stdin,stdout,stderr3個文件描述符,因為我們在conns管理的形式類似一個hash的形式,每個tcp_conn的對應的數組下標就是當前tcp_conn的connfd文件描述符,所以我們應該開辟足夠的大的寬度的數組來滿足下標要求,所以要多開辟3個。雖然這里0,1,2下標在conns永遠用不上。 ### 7.3 創建鏈接判斷鏈接數量 ? 我們在tcp_server在accept成功之后,判斷鏈接數量,如果滿足需求將連接創建起來,并添加到conns中。 > lars_reactor/src/tcp_server.cpp ```c //開始提供創建鏈接服務 void tcp_server::do_accept() { int connfd; while(true) { //accept與客戶端創建鏈接 printf("begin accept\n"); connfd = accept(_sockfd, (struct sockaddr*)&_connaddr, &_addrlen); if (connfd == -1) { if (errno == EINTR) { fprintf(stderr, "accept errno=EINTR\n"); continue; } else if (errno == EMFILE) { //建立鏈接過多,資源不夠 fprintf(stderr, "accept errno=EMFILE\n"); } else if (errno == EAGAIN) { fprintf(stderr, "accept errno=EAGAIN\n"); break; } else { fprintf(stderr, "accept error"); exit(1); } } else { // =========================================== //accept succ! int cur_conns; get_conn_num(&cur_conns); //1 判斷鏈接數量 if (cur_conns >= _max_conns) { fprintf(stderr, "so many connections, max = %d\n", _max_conns); close(connfd); } else { tcp_conn *conn = new tcp_conn(connfd, _loop); if (conn == NULL) { fprintf(stderr, "new tcp_conn error\n"); exit(1); } printf("get new connection succ!\n"); } // =========================================== break; } } } ``` ### 7.4 對鏈接數量進行內部統計 在tcp_conn創建時,將tcp_server中的conns增加。 > lars_reactor/src/tcp_conn.cpp ```c //初始化tcp_conn tcp_conn::tcp_conn(int connfd, event_loop *loop) { _connfd = connfd; _loop = loop; //1. 將connfd設置成非阻塞狀態 int flag = fcntl(_connfd, F_GETFL, 0); fcntl(_connfd, F_SETFL, O_NONBLOCK|flag); //2. 設置TCP_NODELAY禁止做讀寫緩存,降低小包延遲 int op = 1; setsockopt(_connfd, IPPROTO_TCP, TCP_NODELAY, &op, sizeof(op));//need netinet/in.h netinet/tcp.h //3. 將該鏈接的讀事件讓event_loop監控 _loop->add_io_event(_connfd, conn_rd_callback, EPOLLIN, this); // ============================ //4 將該鏈接集成到對應的tcp_server中 tcp_server::increase_conn(_connfd, this); // ============================ } ``` 在tcp_conn銷毀時,將tcp_server中的conns減少。 > lars_reactor/src/tcp_conn.cpp ```c //銷毀tcp_conn void tcp_conn::clean_conn() { //鏈接清理工作 //1 將該鏈接從tcp_server摘除掉 tcp_server::decrease_conn(_connfd); //2 將該鏈接從event_loop中摘除 _loop->del_io_event(_connfd); //3 buf清空 ibuf.clear(); obuf.clear(); //4 關閉原始套接字 int fd = _connfd; _connfd = -1; close(fd); } ``` ### 7.5 完成Lars Reactor V0.5開發 ? server和client 應用app端的代碼和v0.4一樣,這里我們先修改tcp_server中的MAX_CONN宏為 > lars_reacotr/include/tcp_server.h ```c #define MAX_CONNS 2 ``` 方便我們測試。這個這個數值是要在配置文件中可以配置的。 我們啟動服務端,然后分別啟動兩個client可以正常連接。 當我們啟動第三個就發現已經連接不上。然后server端會打出如下結果. ```bash so many connections, max = 2 ``` --- ### 關于作者: 作者:`Aceld(劉丹冰)` mail: [danbing.at@gmail.com](mailto:danbing.at@gmail.com) github: [https://github.com/aceld](https://github.com/aceld) 原創書籍: [http://www.hmoore.net/@aceld](http://www.hmoore.net/@aceld) ![](https://img.kancloud.cn/b0/d1/b0d11a21ba62e96aef1c11d5bfff2cf8_227x227.jpg) >**原創聲明:未經作者允許請勿轉載, 如果轉載請注明出處**
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看