LIBUV学习笔记(三)libuv中pipe/tty相关操作以及一个简单的unix域回射服务器/客户端例子...

uv_pipe_t — Pipe handle

Pipe handles provide an abstraction over local domain sockets on Unix and named pipes on Windows.

libuv中的uv_pipe起到的是unix like系统中unix域socket以及windows中命名管道的抽象封装,也就意味着我们可以使用这一工具简单的实现进程间通讯(IPC)。

主要有以下几个API:

int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc)

  初始化一个pipe handle,ipc指示了该管道是否会用来进行进程间handle传输(这里应该指的是进程间文件描述符传递吧?Unix域socket之间的)。

int uv_pipe_open(uv_pipe_t* handle, uv_file file)

  打开现存的文件描述符,会被设置成非阻塞模式

int uv_pipe_bind(uv_pipe_t* handle, const char* name)

  绑定到路径(名字)

void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb)

  连接(connect)到指定pipe,并调用回调cb

int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size)

  获得指定pipe绑定的sockname

int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size)

  获得pipe连接的sockname(服务器端)

 

uv_tty_t — TTY handle

TTY handles represent a stream for the console.

TTY抽象绑定了指定的终端流,uv_tty_t同样是uv_stream_t的子类

主要API有:

int uv_tty_init(uv_loop_t* loop, uv_tty_t* handle, uv_file fd, int readable)

  tty handle初始化,fd的常用值为

  • 0 = stdin
  • 1 = stdout
  • 2 = stderr

int uv_tty_set_mode(uv_tty_t* handle, uv_tty_mode_t mode)

  改变tty模式

其他操作和普通stream差不多。

 

简单的unix域回射服务器/客户断例子

libuv的官方源码给出了一个基于uv_pipe的echo服务器端程序,我自己写了一个基于tty和pipe的回射客户端,下面来看源码:

pipe-echo-server.c

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <uv.h>
 5 
 6 uv_loop_t *loop;
 7 
 8 typedef struct {
 9     uv_write_t req;
10     uv_buf_t buf;
11 } write_req_t;
12 
13 void free_write_req(uv_write_t *req) {
14     write_req_t *wr = (write_req_t*) req;
15     free(wr->buf.base);
16     free(wr);
17 }
18 
19 void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {//用于读数据时的缓冲区分配
20   buf->base = (char*)malloc(suggested_size);
21   buf->len = suggested_size;
22 }
23 
24 void echo_write(uv_write_t *req, int status) {
25     if (status < 0) {
26         fprintf(stderr, "Write error %s\n", uv_err_name(status));
27     }
28     free_write_req(req);
29 }
30 
31 void echo_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) {
32     if (nread > 0) {
33         write_req_t *req = (write_req_t*) malloc(sizeof(write_req_t));
34         req->buf = uv_buf_init(buf->base, nread);//这是个构造函数,这里仅仅是浅拷贝!指针只是进行了赋值而已!!!
35         uv_write((uv_write_t*) req, client, &req->buf, 1, echo_write);
36         return;
37     }
38 
39     if (nread < 0) {
40         if (nread != UV_EOF)
41             fprintf(stderr, "Read error %s\n", uv_err_name(nread));
42         uv_close((uv_handle_t*) client, NULL);
43     }
44 
45     free(buf->base);
46 }
47 
48 void on_new_connection(uv_stream_t *server, int status) {
49     if (status == -1) {
50         // error!
51         return;
52     }
53 
54     uv_pipe_t *client = (uv_pipe_t*) malloc(sizeof(uv_pipe_t));
55     uv_pipe_init(loop, client, 0);
56     if (uv_accept(server, (uv_stream_t*) client) == 0) {//accept成功之后开始读
57         uv_read_start((uv_stream_t*) client, alloc_buffer, echo_read);//开始从pipe读(在loop中注册读事件),读完回调
58     }
59     else {
60         uv_close((uv_handle_t*) client, NULL);//出错关闭
61     }
62 }
63 
64 void remove_sock(int sig) {
65     uv_fs_t req;
66     uv_fs_unlink(loop, &req, "echo.sock", NULL);//删除操作
67     exit(0);
68 }
69 
70 int main() {
71     loop = uv_default_loop();
72 
73     uv_pipe_t server;
74     uv_pipe_init(loop, &server, 0);
75 
76     signal(SIGINT, remove_sock);//收到结束信号顺便删除相关pipe文件
77 
78     int r;
79     if ((r = uv_pipe_bind(&server, "echo.sock"))) {//服务器端绑定unix域地址
80         fprintf(stderr, "Bind error %s\n", uv_err_name(r));
81         return 1;
82     }
83     if ((r = uv_listen((uv_stream_t*) &server, 128, on_new_connection))) {//开始连接,出现回调,enent loop由此开始
84         fprintf(stderr, "Listen error %s\n", uv_err_name(r));
85         return 2;
86     }
87     return uv_run(loop, UV_RUN_DEFAULT);
88 }

接下来是客户端代码:

pipe-echo-client.c(自己写的,仅供参考,很多异常处理代码都省略了)

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <uv.h>
 5 
 6 uv_loop_t * loop;
 7 uv_tty_t tty_stdin,tty_stdout;
 8 uv_pipe_t server;
 9 
10 typedef struct {//该结构存在的意义就是向回调函数传递缓冲区地址,并及时释放
11     uv_write_t req;
12     uv_buf_t buf;
13 } write_req_t;
14 
15 void free_write_req(uv_write_t *req) {
16     write_req_t *wr = (write_req_t*) req;
17     free(wr->buf.base);
18     free(wr);
19 }
20 
21 void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
22   buf->base = (char*)malloc(suggested_size);
23   buf->len = suggested_size;
24 }
25 
26 void write_to_stdout_cb(uv_write_t* req, int status){
27     if(status){
28         fprintf(stderr, "Write error %s\n", uv_strerror(status));
29         exit(0);
30     }
31     free_write_req(req);
32 }
33 
34 void read_from_pipe_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf){
35     write_req_t *wri = (write_req_t *)malloc(sizeof(write_req_t));
36     wri->buf = uv_buf_init(buf->base,nread);
37     uv_write((uv_write_t*)wri,(uv_stream_t*)&tty_stdout,&wri->buf,1,write_to_stdout_cb);
38 }
39 
40 void write_to_pipe_cb(uv_write_t* req, int status){
41     if(status){
42         fprintf(stderr, "Write error %s\n", uv_strerror(status));
43         exit(0);
44     }
45     uv_read_start((uv_stream_t*)&server,alloc_buffer,read_from_pipe_cb);//再一次构造缓冲区
46     free_write_req(req);//释放动态分配的所有数据
47 }
48 
49 void read_from_input_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf){
50     write_req_t *wri = (write_req_t *)malloc(sizeof(write_req_t));//实例化新结构,主要2个作用:产生write所需的uv_write_t;临时存储buf(同时提供给回调函数析构方法)便于该数据的及时free
51     wri->buf=uv_buf_init(buf->base, nread);//buf复制
52     uv_write((uv_write_t*)wri,(uv_stream_t*)&server,&wri->buf,1,write_to_pipe_cb);//需要注意的是write调用的时候&wri->buf必须依然有效!所以这里直接用buf会出现问题!
53     //write完成之后当前缓冲区也就失去了意义,于是向回调函数传递buf指针,并由回调函数负责析构该缓冲区
54 }
55 
56 int main() {
57     loop = uv_default_loop();
58     
59     uv_pipe_init(loop, &server, 1);
60     uv_tty_init(loop,&tty_stdin,0,1);
61     uv_tty_init(loop,&tty_stdout,1,0);
62 
63     uv_connect_t conn;
64     uv_pipe_connect((uv_connect_t*)&conn,&server,"echo.sock",NULL);//连接pipe
65     uv_read_start((uv_stream_t*)&tty_stdin,alloc_buffer,read_from_input_cb);//从stdin读数据,并由此触发回调,每次alloc_buffer回调产生一个缓冲数据结构uv_buf_t并在堆上分配数据!
66 
67     return uv_run(loop, UV_RUN_DEFAULT);
68 }

一些注释已经写在代码旁边了,特别需要注意的就是回调函数的调用时机与非阻塞调用的流程,以及buffer相关的操作。。。坑挺多的,也只有一步一步踩过才能真正算懂。

转载于:https://www.cnblogs.com/J1ac/p/9046893.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值