libuv库TCP echo-server

学习libuv库,写TCP echo-server

大部分代码都来自libuv源码test目录下echo-server.c文件。

我自己添加了一点代码,通过uv_read_start函数更改read_cb函数

使得第奇数次客户端输入一行文字后,服务端原样返回,

偶数次输入一行文字,服务端将输入的一行文字逆序后返回

结果如下:

cheng@debian:~$ telnet 127.0.0.1 7890
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
helo
helo
helo
oleh
00000111111
00000111111
00000111111
11111100000


---------------------------------------------------------总结的分割线---------------------------------------------------------------------------------

通过echo-server这个程序,可以学习怎么利用libuv,像完成原始socket网络编程那样,

创建socket, bind, listen, accept过程。

只是在异步,非阻塞的方式编程时,需要通过事先为某个事件发生时应该调用的回调

在echo-server程序中,通过uv_listen函数注册连接回调函数

uv_read_start注册读函数

uv_write注册写函数

在头文件uv.h看这三个函数的函数原型,可以很清楚的知道每个参数的意义

------------------------------------------------------------------------------------------------------------------------------------------------------------

修改过的echo-server.c代码:

[cpp]  view plain copy
  1. /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. 
  2.  * 
  3.  * Permission is hereby granted, free of charge, to any person obtaining a copy 
  4.  * of this software and associated documentation files (the "Software"), to 
  5.  * deal in the Software without restriction, including without limitation the 
  6.  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 
  7.  * sell copies of the Software, and to permit persons to whom the Software is 
  8.  * furnished to do so, subject to the following conditions: 
  9.  * 
  10.  * The above copyright notice and this permission notice shall be included in 
  11.  * all copies or substantial portions of the Software. 
  12.  * 
  13.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
  14.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
  15.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
  16.  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
  17.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
  18.  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
  19.  * IN THE SOFTWARE. 
  20.  */  
  21.   
  22. #include   
  23. #include   
  24. #include   
  25. #include   
  26. #include   
  27.   
  28. #define ASSERT assert  
  29. #define TEST_PORT 7890  
  30.   
  31.   
  32. static void reversed(char *s, int len)  
  33. {  
  34.     char c;  
  35.     char *end;  
  36.     end = s + len - 1;  
  37.     while (*end == '\r' || *end == '\n') {  
  38.         end--;  
  39.     }  
  40.     while (end > s) {  
  41.         c = *end;  
  42.         *end = *s;  
  43.         *s = c;  
  44.         end--;  
  45.         s++;  
  46.     }  
  47. }  
  48.   
  49.   
  50. typedef struct {  
  51.   uv_write_t req;  
  52.   uv_buf_t buf;  
  53. } write_req_t;  
  54.   
  55. #define FATAL(msg)                                        \  
  56.   do {                                                    \  
  57.     fprintf(stderr,                                       \  
  58.             "Fatal error in %s on line %d: %s\n",         \  
  59.             __FILE__,                                     \  
  60.             __LINE__,                                     \  
  61.             msg);                                         \  
  62.     fflush(stderr);                                       \  
  63.     abort();                                              \  
  64.   } while (0)  
  65.   
  66. typedef enum {  
  67.     TCP = 0,  
  68.     UDP,  
  69.     PIPE  
  70. } stream_type;  
  71.   
  72. static uv_loop_t* loop;  
  73.   
  74. static int server_closed;  
  75. static stream_type serverType;  
  76. static uv_tcp_t tcpServer;  
  77. static uv_udp_t udpServer;  
  78. static uv_pipe_t pipeServer;  
  79. static uv_handle_t* server;  
  80.   
  81. static void after_write(uv_write_t* req, int status);  
  82. static void after_read(uv_stream_t*, ssize_t nread, uv_buf_t buf);  
  83. static void on_close(uv_handle_t* peer);  
  84. static void on_server_close(uv_handle_t* handle);  
  85. static void on_connection(uv_stream_t*, int status);  
  86. static uv_buf_t echo_alloc(uv_handle_t* handle, size_t suggested_size);  
  87. static void after_read(uv_stream_t* handle, ssize_t nread, uv_buf_t buf);  
  88. static void after_read_2(uv_stream_t* handle, ssize_t nread, uv_buf_t buf);  
  89.   
  90. static void after_write(uv_write_t* req, int status) {  
  91.   write_req_t* wr;  
  92.   uv_err_t err;  
  93.   
  94.   /* Free the read/write buffer and the request */  
  95.   wr = (write_req_t*) req;  
  96.   free(wr->buf.base);  
  97.   free(wr);  
  98.   
  99.   if (status == 0)  
  100.     return;  
  101.   
  102.   err = uv_last_error(loop);  
  103.   fprintf(stderr, "uv_write error: %s\n", uv_strerror(err));  
  104.   
  105.   if (err.code == UV_ECANCELED)  
  106.     return;  
  107.   
  108.   ASSERT(err.code == UV_EPIPE);  
  109.   uv_close((uv_handle_t*)req->handle, on_close);  
  110. }  
  111.   
  112.   
  113. static void after_shutdown(uv_shutdown_t* req, int status) {  
  114.   uv_close((uv_handle_t*)req->handle, on_close);  
  115.   free(req);  
  116. }  
  117.   
  118.   
  119. static void after_read(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) {  
  120.   int i;  
  121.   write_req_t *wr;  
  122.   uv_shutdown_t* req;  
  123.   int r;  
  124.   
  125.   if (nread < 0) {  
  126.     /* Error or EOF */  
  127.     ASSERT (uv_last_error(loop).code == UV_EOF);  
  128.   
  129.     if (buf.base) {  
  130.       free(buf.base);  
  131.     }  
  132.   
  133.     req = (uv_shutdown_t*) malloc(sizeof *req);  
  134.     uv_shutdown(req, handle, after_shutdown);  
  135.   
  136.     return;  
  137.   }  
  138.   
  139.   if (nread == 0) {  
  140.     /* Everything OK, but nothing read. */  
  141.     free(buf.base);  
  142.     return;  
  143.   }  
  144.   
  145.   /* 
  146.    * Scan for the letter Q which signals that we should quit the server. 
  147.    * If we get QS it means close the stream. 
  148.    */  
  149.   if (!server_closed) {  
  150.     for (i = 0; i < nread; i++) {  
  151.       if (buf.base[i] == 'Q') {  
  152.         if (i + 1 < nread && buf.base[i + 1] == 'S') {  
  153.           free(buf.base);  
  154.           uv_close((uv_handle_t*)handle, on_close);  
  155.           return;  
  156.         } else {  
  157.           uv_close(server, on_server_close);  
  158.           server_closed = 1;  
  159.         }  
  160.       }  
  161.     }  
  162.   }  
  163.   
  164.   wr = (write_req_t*) malloc(sizeof *wr);  
  165.   
  166.   wr->buf = uv_buf_init(buf.base, nread);  
  167.   if (uv_write(&wr->req, handle, &wr->buf, 1, after_write)) {  
  168.     FATAL("uv_write failed");  
  169.   }  
  170.   
  171.   r = uv_read_start(handle, echo_alloc, after_read_2);  
  172.   ASSERT(r == 0);  
  173. }  
  174.   
  175. static void after_read_2(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) {  
  176.   int i;  
  177.   write_req_t *wr;  
  178.   uv_shutdown_t* req;  
  179.   int r;  
  180.   
  181.   if (nread < 0) {  
  182.     /* Error or EOF */  
  183.     ASSERT (uv_last_error(loop).code == UV_EOF);  
  184.   
  185.     if (buf.base) {  
  186.       free(buf.base);  
  187.     }  
  188.   
  189.     req = (uv_shutdown_t*) malloc(sizeof *req);  
  190.     uv_shutdown(req, handle, after_shutdown);  
  191.   
  192.     return;  
  193.   }  
  194.   
  195.   if (nread == 0) {  
  196.     /* Everything OK, but nothing read. */  
  197.     free(buf.base);  
  198.     return;  
  199.   }  
  200.   
  201.   /* 
  202.    * Scan for the letter Q which signals that we should quit the server. 
  203.    * If we get QS it means close the stream. 
  204.    */  
  205.   if (!server_closed) {  
  206.     for (i = 0; i < nread; i++) {  
  207.       if (buf.base[i] == 'Q') {  
  208.         if (i + 1 < nread && buf.base[i + 1] == 'S') {  
  209.           free(buf.base);  
  210.           uv_close((uv_handle_t*)handle, on_close);  
  211.           return;  
  212.         } else {  
  213.           uv_close(server, on_server_close);  
  214.           server_closed = 1;  
  215.         }  
  216.       }  
  217.     }  
  218.   }  
  219.   
  220.   wr = (write_req_t*) malloc(sizeof *wr);  
  221.   reversed(buf.base, nread);  
  222.   wr->buf = uv_buf_init(buf.base, nread);  
  223.   if (uv_write(&wr->req, handle, &wr->buf, 1, after_write)) {  
  224.     FATAL("uv_write failed");  
  225.   }  
  226.   
  227.   r = uv_read_start(handle, echo_alloc, after_read);  
  228.   ASSERT(r == 0);  
  229. }  
  230.   
  231.   
  232. static void on_close(uv_handle_t* peer) {  
  233.   free(peer);  
  234. }  
  235.   
  236.   
  237. static uv_buf_t echo_alloc(uv_handle_t* handle, size_t suggested_size) {  
  238.   return uv_buf_init(malloc(suggested_size), suggested_size);  
  239. }  
  240.   
  241.   
  242. static void on_connection(uv_stream_t* server, int status) {  
  243.   uv_stream_t* stream;  
  244.   int r;  
  245.   
  246.   if (status != 0) {  
  247.     fprintf(stderr, "Connect error %d\n",  
  248.         uv_last_error(loop).code);  
  249.   }  
  250.   ASSERT(status == 0);  
  251.   
  252.   switch (serverType) {  
  253.   case TCP:  
  254.     stream = malloc(sizeof(uv_tcp_t));  
  255.     ASSERT(stream != NULL);  
  256.     r = uv_tcp_init(loop, (uv_tcp_t*)stream);  
  257.     ASSERT(r == 0);  
  258.     break;  
  259.   
  260.   case PIPE:  
  261.     stream = malloc(sizeof(uv_pipe_t));  
  262.     ASSERT(stream != NULL);  
  263.     r = uv_pipe_init(loop, (uv_pipe_t*)stream, 0);  
  264.     ASSERT(r == 0);  
  265.     break;  
  266.   
  267.   default:  
  268.     ASSERT(0 && "Bad serverType");  
  269.     abort();  
  270.   }  
  271.   
  272.   /* associate server with stream */  
  273.   stream->data = server;  
  274.   
  275.   r = uv_accept(server, stream);  
  276.   ASSERT(r == 0);  
  277.   
  278.   r = uv_read_start(stream, echo_alloc, after_read);  
  279.   ASSERT(r == 0);  
  280. }  
  281.   
  282.   
  283. static void on_server_close(uv_handle_t* handle) {  
  284.   ASSERT(handle == server);  
  285. }  
  286.   
  287.   
  288. static void on_send(uv_udp_send_t* req, int status);  
  289.   
  290.   
  291. static void on_recv(uv_udp_t* handle,  
  292.                     ssize_t nread,  
  293.                     uv_buf_t buf,  
  294.                     struct sockaddr* addr,  
  295.                     unsigned flags) {  
  296.   uv_udp_send_t* req;  
  297.   int r;  
  298.   
  299.   ASSERT(nread > 0);  
  300.   ASSERT(addr->sa_family == AF_INET);  
  301.   
  302.   req = malloc(sizeof(*req));  
  303.   ASSERT(req != NULL);  
  304.   
  305.   r = uv_udp_send(req, handle, &buf, 1, *(struct sockaddr_in*)addr, on_send);  
  306.   ASSERT(r == 0);  
  307. }  
  308.   
  309.   
  310. static void on_send(uv_udp_send_t* req, int status) {  
  311.   ASSERT(status == 0);  
  312.   free(req);  
  313. }  
  314.   
  315.   
  316. static int tcp4_echo_start(int port) {  
  317.   struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", port);  
  318.   int r;  
  319.   
  320.   server = (uv_handle_t*)&tcpServer;  
  321.   serverType = TCP;  
  322.   
  323.   r = uv_tcp_init(loop, &tcpServer);  
  324.   if (r) {  
  325.     /* TODO: Error codes */  
  326.     fprintf(stderr, "Socket creation error\n");  
  327.     return 1;  
  328.   }  
  329.   
  330.   r = uv_tcp_bind(&tcpServer, addr);  
  331.   if (r) {  
  332.     /* TODO: Error codes */  
  333.     fprintf(stderr, "Bind error\n");  
  334.     return 1;  
  335.   }  
  336.   
  337.   r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection);  
  338.   if (r) {  
  339.     /* TODO: Error codes */  
  340.     fprintf(stderr, "Listen error %s\n",  
  341.         uv_err_name(uv_last_error(loop)));  
  342.     return 1;  
  343.   }  
  344.   
  345.   return 0;  
  346. }  
  347.   
  348. int main()  
  349. {  
  350.   loop = uv_default_loop();  
  351.   
  352.   if (tcp4_echo_start(TEST_PORT))  
  353.     return 1;  
  354.   
  355.   uv_run(loop, UV_RUN_DEFAULT);  
  356.   return 0;  
  357. }  

你可能感兴趣的:(Linux)