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

您所在的位置:网站首页 unix的作用 LIBUV学习笔记(三)libuv中pipe/tty相关操作以及一个简单的unix域回射服务器/客户端例子...

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

#LIBUV学习笔记(三)libuv中pipe/tty相关操作以及一个简单的unix域回射服务器/客户端例子...| 来源: 网络整理| 查看: 265

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 2 #include 3 #include 4 #include 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 2 #include 3 #include 4 #include 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相关的操作。。。坑挺多的,也只有一步一步踩过才能真正算懂。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3