<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>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## 9) 鏈接創建/銷毀Hook機制 ? 下面我們來給鏈接注冊兩個hook節點的函數,即服務端有新的客戶端鏈接創建之后用戶可以注冊一個回調,有客戶端斷開鏈接的回調。還有客戶端在成功與服務端創建鏈接之后創建的回調,和客戶端與服務端斷開鏈接之前的回調。 ### 9.1 tcp_server服務端添加鏈接Hook函數 #### A. 定義Hook函數原型 > lars_reactor/include/net_connection.h ```c #pragma once /* * * 網絡通信的抽象類,任何需要進行收發消息的模塊,都可以實現該類 * * */ class net_connection { public: net_connection() {} //發送消息的接口 virtual int send_message(const char *data, int datalen, int msgid) = 0; }; //創建鏈接/銷毀鏈接 要觸發的 回調函數類型 typedef void (*conn_callback)(net_connection *conn, void *args); ``` #### B. tcp_server定義相關hook函數的屬性 > lars_reactor/include/tcp_server.h ```c #pragma once #include <netinet/in.h> #include "event_loop.h" #include "tcp_conn.h" #include "message.h" class tcp_server { public: //server的構造函數 tcp_server(event_loop* loop, const char *ip, uint16_t port); //開始提供創建鏈接服務 void do_accept(); //鏈接對象釋放的析構 ~tcp_server(); //注冊消息路由回調函數 void add_msg_router(int msgid, msg_callback *cb, void *user_data = NULL) { router.register_msg_router(msgid, cb, user_data); } private: //基礎信息 int _sockfd; //套接字 struct sockaddr_in _connaddr; //客戶端鏈接地址 socklen_t _addrlen; //客戶端鏈接地址長度 //event_loop epoll事件機制 event_loop* _loop; public: //---- 消息分發路由 ---- static msg_router router; //---- 客戶端鏈接管理部分----- 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; //全部已經在線的連接信息 // ------- 創建鏈接/銷毀鏈接 Hook 部分 ----- //設置鏈接的創建hook函數 static void set_conn_start(conn_callback cb, void *args = NULL) { conn_start_cb = cb; conn_start_cb_args = args; } //設置鏈接的銷毀hook函數 static void set_conn_close(conn_callback cb, void *args = NULL) { conn_close_cb = cb; conn_close_cb_args = args; } //創建鏈接之后要觸發的 回調函數 static conn_callback conn_start_cb; static void *conn_start_cb_args; //銷毀鏈接之前要觸發的 回調函數 static conn_callback conn_close_cb; static void *conn_close_cb_args; private: //TODO //從配置文件中讀取 #define MAX_CONNS 10000 static int _max_conns; //最大client鏈接個數 static int _curr_conns; //當前鏈接刻度 static pthread_mutex_t _conns_mutex; //保護_curr_conns刻度修改的鎖 }; ``` #### C. tcp_conn在連接創建/銷毀調用Hook函數 ```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 //2.5 如果用戶注冊了鏈接建立Hook 則調用 if (tcp_server::conn_start_cb) { tcp_server::conn_start_cb(this, tcp_server::conn_start_cb_args); } //3. 將該鏈接的讀事件讓event_loop監控 _loop->add_io_event(_connfd, conn_rd_callback, EPOLLIN, this); //4 將該鏈接集成到對應的tcp_server中 tcp_server::increase_conn(_connfd, this); } //... //... //銷毀tcp_conn void tcp_conn::clean_conn() { // 如果注冊了鏈接銷毀Hook函數,則調用 if (tcp_server::conn_close_cb) { tcp_server::conn_close_cb(this, tcp_server::conn_close_cb_args); } //鏈接清理工作 //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); } ``` ### 9.2 tcp_client客戶端添加鏈接Hook函數 #### A. tcp_client添加Hook屬性 > lars_reactor/include/tcp_client.h ```c #pragma once #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include "io_buf.h" #include "event_loop.h" #include "message.h" #include "net_connection.h" class tcp_client : public net_connection { public: //初始化客戶端套接字 tcp_client(event_loop *loop, const char *ip, unsigned short port, const char *name); //發送message方法 int send_message(const char *data, int msglen, int msgid); //創建鏈接 void do_connect(); //處理讀業務 int do_read(); //處理寫業務 int do_write(); //釋放鏈接資源 void clean_conn(); ~tcp_client(); //設置業務處理回調函數 //void set_msg_callback(msg_callback *msg_cb) //{ //this->_msg_callback = msg_cb; //} //注冊消息路由回調函數 void add_msg_router(int msgid, msg_callback *cb, void *user_data = NULL) { _router.register_msg_router(msgid, cb, user_data); } //----- 鏈接創建/銷毀回調Hook ---- //設置鏈接的創建hook函數 void set_conn_start(conn_callback cb, void *args = NULL) { _conn_start_cb = cb; _conn_start_cb_args = args; } //設置鏈接的銷毀hook函數 void set_conn_close(conn_callback cb, void *args = NULL) { _conn_close_cb = cb; _conn_close_cb_args = args; } //創建鏈接之后要觸發的 回調函數 conn_callback _conn_start_cb; void * _conn_start_cb_args; //銷毀鏈接之前要觸發的 回調函數 conn_callback _conn_close_cb; void * _conn_close_cb_args; // --------------------------------- bool connected; //鏈接是否創建成功 //server端地址 struct sockaddr_in _server_addr; io_buf _obuf; io_buf _ibuf; private: int _sockfd; socklen_t _addrlen; //處理消息的分發路由 msg_router _router; //msg_callback *_msg_callback; //單路由模式去掉 //客戶端的事件處理機制 event_loop* _loop; //當前客戶端的名稱 用戶記錄日志 const char *_name; }; ``` #### B. tcp_client在創建/銷毀調用Hook > lars_reactor/src/tcp_client.c ```c //創建鏈接 void tcp_client::do_connect() { // ... // ... int ret = connect(_sockfd, (const struct sockaddr*)&_server_addr, _addrlen); if (ret == 0) { //鏈接創建成功 connected = true; //調用開發者客戶端注冊的創建鏈接之后的hook函數 if (_conn_start_cb != NULL) { _conn_start_cb(this, _conn_start_cb_args); } // ... // ... } } //判斷鏈接是否是創建鏈接,主要是針對非阻塞socket 返回EINPROGRESS錯誤 static void connection_delay(event_loop *loop, int fd, void *args) { tcp_client *cli = (tcp_client*)args; loop->del_io_event(fd); int result = 0; socklen_t result_len = sizeof(result); getsockopt(fd, SOL_SOCKET, SO_ERROR, &result, &result_len); if (result == 0) { //鏈接是建立成功的 cli->connected = true; printf("connect %s:%d succ!\n", inet_ntoa(cli->_server_addr.sin_addr), ntohs(cli->_server_addr.sin_port)); //調用開發者注冊的創建鏈接Hook函數 if (cli->_conn_start_cb != NULL) { cli->_conn_start_cb(cli, cli->_conn_start_cb_args); } // .... // ... } } //釋放鏈接資源,重置連接 void tcp_client::clean_conn() { if (_sockfd != -1) { printf("clean conn, del socket!\n"); _loop->del_io_event(_sockfd); close(_sockfd); } connected = false; //調用開發者注冊的銷毀鏈接之前觸發的Hook if (_conn_close_cb != NULL) { _conn_close_cb(this, _conn_close_cb_args); } //重新連接 this->do_connect(); } ``` ### 9.3 完成Lars Reactor V0.7開發 > server.cpp ```c #include "tcp_server.h" #include <string.h> //回顯業務的回調函數 void callback_busi(const char *data, uint32_t len, int msgid, net_connection *conn, void *user_data) { printf("callback_busi ...\n"); //直接回顯 conn->send_message(data, len, msgid); } //打印信息回調函數 void print_busi(const char *data, uint32_t len, int msgid, net_connection *conn, void *user_data) { printf("recv client: [%s]\n", data); printf("msgid: [%d]\n", msgid); printf("len: [%d]\n", len); } //新客戶端創建的回調 void on_client_build(net_connection *conn, void *args) { int msgid = 101; const char *msg = "welcome! you online.."; conn->send_message(msg, strlen(msg), msgid); } //客戶端銷毀的回調 void on_client_lost(net_connection *conn, void *args) { printf("connection is lost !\n"); } int main() { event_loop loop; tcp_server server(&loop, "127.0.0.1", 7777); //注冊消息業務路由 server.add_msg_router(1, callback_busi); server.add_msg_router(2, print_busi); //注冊鏈接hook回調 server.set_conn_start(on_client_build); server.set_conn_close(on_client_lost); loop.event_process(); return 0; } ``` > client.cpp ```c #include "tcp_client.h" #include <stdio.h> #include <string.h> //客戶端業務 void busi(const char *data, uint32_t len, int msgid, net_connection *conn, void *user_data) { //得到服務端回執的數據 printf("recv server: [%s]\n", data); printf("msgid: [%d]\n", msgid); printf("len: [%d]\n", len); } //客戶端銷毀的回調 void on_client_build(net_connection *conn, void *args) { int msgid = 1; const char *msg = "Hello Lars!"; conn->send_message(msg, strlen(msg), msgid); } //客戶端銷毀的回調 void on_client_lost(net_connection *conn, void *args) { printf("on_client_lost...\n"); printf("Client is lost!\n"); } int main() { event_loop loop; //創建tcp客戶端 tcp_client client(&loop, "127.0.0.1", 7777, "clientv0.6"); //注冊消息路由業務 client.add_msg_router(1, busi); client.add_msg_router(101, busi); //設置hook函數 client.set_conn_start(on_client_build); client.set_conn_close(on_client_lost); //開啟事件監聽 loop.event_process(); return 0; } ``` 運行結果 服務端 ```bash $ ./server msg_router init... add msg cb msgid = 1 add msg cb msgid = 2 begin accept get new connection succ! read data: Hello Lars! call msgid = 1 callback_busi ... ======= connection closed by peer connection is lost ! ``` 客戶端: ```bash $ ./client msg_router init... do_connect EINPROGRESS add msg cb msgid = 1 add msg cb msgid = 101 connect 127.0.0.1:7777 succ! do write over, del EPOLLOUT call msgid = 101 recv server: [welcome! you online..] msgid: [101] len: [21] ======= call msgid = 1 recv server: [Hello Lars!] msgid: [1] len: [11] ======= ^C ``` ? 這樣我們的成功的將hook機制加入進去了。 --- ### 關于作者: 作者:`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>

                              哎呀哎呀视频在线观看