Linux高并发网络编程开发——libevent
在学习Linux高并发网络编程开发总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。
10-Linux系统编程-第15天(libevent)
目录:
一、学习目标
二、代码分析(epoll_loop.c)
三、libevent
1、libevent的安装和测试
2、解决动态库找不到的问题
3、event_base讲解
4、event_base相关的小函数
5、event事件的创建
6、消息循环
7、libevent内部事件的状态转换
8、使用event读管道
9、使用event写管道
10、bufferevent介绍
11、bufferevent函数介绍
12、evconnlistener链接监听器
13、bufferevent实现服务器端代码
技巧:代码片段(c.snippets)
四、重要函数总结
一、学习目标
二、代码分析
》分析程序(epoll_loop.c):
1 /* 2 * epoll基于非阻塞I/O事件驱动 3 */ 4 #include <stdio.h> 5 #include <sys/socket.h> 6 #include <sys/epoll.h> 7 #include <arpa/inet.h> 8 #include <fcntl.h> 9 #include <unistd.h> 10 #include <errno.h> 11 #include <string.h> 12 #include <stdlib.h> 13 #include <time.h> 14 15 #define MAX_EVENTS 1024 //监听上限数 16 #define BUFLEN 4096 17 #define SERV_PORT 8080 18 19 void recvdata(int fd, int events, void *arg); 20 void senddata(int fd, int events, void *arg); 21 22 /* 描述就绪文件描述符相关信息 */ 23 24 struct myevent_s { 25 int fd; //要监听的文件描述符 26 int events; //对应的监听事件 27 void *arg; //泛型参数 28 void (*call_back)(int fd, int events, void *arg); //回调函数 29 int status; //是否在监听:1->在红黑树上(监听), 0->不在(不监听) 30 char buf[BUFLEN]; 31 int len; 32 long last_active; //记录每次加入红黑树 g_efd 的时间值 33 }; 34 35 int g_efd; //全局变量, 保存epoll_create返回的文件描述符 36 struct myevent_s g_events[MAX_EVENTS+1]; //自定义结构体类型数组. +1-->listen fd 37 38 39 /*将结构体 myevent_s 成员变量 初始化*/ 40 41 void eventset(struct myevent_s *ev, int fd, void (*call_back)(int, int, void *), void *arg) 42 { 43 ev->fd = fd; 44 ev->call_back = call_back; 45 ev->events = 0; 46 ev->arg = arg; 47 ev->status = 0; 48 //memset(ev->buf, 0, sizeof(ev->buf)); 49 //ev->len = 0; 50 ev->last_active = time(NULL); //调用eventset函数的时间 51 52 return; 53 } 54 55 /* 向 epoll监听的红黑树 添加一个 文件描述符 */ 56 57 void eventadd(int efd, int events, struct myevent_s *ev) 58 { 59 struct epoll_event epv = {0, {0}}; 60 int op; 61 epv.data.ptr = ev; 62 epv.events = ev->events = events; //EPOLLIN 或 EPOLLOUT 63 64 if (ev->status == 1) { //已经在红黑树 g_efd 里 65 op = EPOLL_CTL_MOD; //修改其属性 66 } else { //不在红黑树里 67 op = EPOLL_CTL_ADD; //将其加入红黑树 g_efd, 并将status置1 68 ev->status = 1; 69 } 70 71 if (epoll_ctl(efd, op, ev->fd, &epv) < 0) //实际添加/修改 72 printf("event add failed [fd=%d], events[%d]\n", ev->fd, events); 73 else 74 printf("event add OK [fd=%d], op=%d, events[%0X]\n", ev->fd, op, events); 75 76 return ; 77 } 78 79 /* 从epoll 监听的 红黑树中删除一个 文件描述符*/ 80 81 void eventdel(int efd, struct myevent_s *ev) 82 { 83 struct epoll_event epv = {0, {0}}; 84 85 if (ev->status != 1) //不在红黑树上 86 return ; 87 88 epv.data.ptr = ev; 89 ev->status = 0; //修改状态 90 epoll_ctl(efd, EPOLL_CTL_DEL, ev->fd, &epv); //从红黑树 efd 上将 ev->fd 摘除 91 92 return ; 93 } 94 95 /* 当有文件描述符就绪, epoll返回, 调用该函数 与客户端建立链接 */ 96 // 回调函数 - 监听的文件描述符发送读事件时被调用 97 void acceptconn(int lfd, int events, void *arg) 98 { 99 struct sockaddr_in cin; 100 socklen_t len = sizeof(cin); 101 int cfd, i; 102 103 if ((cfd = accept(lfd, (struct sockaddr *)&cin, &len)) == -1) { 104 if (errno != EAGAIN && errno != EINTR) { 105 /* 暂时不做出错处理 */ 106 } 107 printf("%s: accept, %s\n", __func__, strerror(errno)); 108 return ; 109 } 110 111 do { 112 for (i = 0; i < MAX_EVENTS; i++) //从全局数组g_events中找一个空闲元素 113 if (g_events[i].status == 0) //类似于select中找值为-1的元素 114 break; //跳出 for 115 116 if (i == MAX_EVENTS) { 117 printf("%s: max connect limit[%d]\n", __func__, MAX_EVENTS); 118 break; //跳出do while(0) 不执行后续代码 119 } 120 121 int flag = 0; 122 if ((flag = fcntl(cfd, F_SETFL, O_NONBLOCK)) < 0) { //将cfd也设置为非阻塞 123 printf("%s: fcntl nonblocking failed, %s\n", __func__, strerror(errno)); 124 break; 125 } 126 127 /* 给cfd设置一个 myevent_s 结构体, 回调函数 设置为 recvdata */ 128 129 eventset(&g_events[i], cfd, recvdata, &g_events[i]); 130 eventadd(g_efd, EPOLLIN, &g_events[i]); //将cfd添加到红黑树g_efd中,监听读事件 131 132 } while(0); 133 134 printf("new connect [%s:%d][time:%ld], pos[%d]\n", 135 inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), g_events[i].last_active, i); 136 return ; 137 } 138 139 // 回调函数 - 通信的文件描述符发生读事件时候被调用 140 void recvdata(int fd, int events, void *arg) 141 { 142 struct myevent_s *ev = (struct myevent_s *)arg; 143 int len; 144 145 len = recv(fd, ev->buf, sizeof(ev->buf), 0); //读文件描述符, 数据存入myevent_s成员buf中 146 147 eventdel(g_efd, ev); //将该节点从红黑树上摘除 148 149 if (len > 0) { 150 151 ev->len = len; 152 ev->buf[len] = '\0'; //手动添加字符串结束标记 153 printf("C[%d]:%s\n", fd, ev->buf); 154 155 eventset(ev, fd, senddata, ev); //设置该 fd 对应的回调函数为 senddata 156 eventadd(g_efd, EPOLLOUT, ev); //将fd加入红黑树g_efd中,监听其写事件 157 158 } else if (len == 0) { 159 close(ev->fd); 160 /* ev-g_events 地址相减得到偏移元素位置 */ 161 printf("[fd=%d] pos[%ld], closed\n", fd, ev-g_events); 162 } else { 163 close(ev->fd); 164 printf("recv[fd=%d] error[%d]:%s\n", fd, errno, strerror(errno)); 165 } 166 167 return; 168 } 169 170 // 回调函数 - 通信的文件描述符发生写事件时候被调用 171 void senddata(int fd, int events, void *arg) 172 { 173 struct myevent_s *ev = (struct myevent_s *)arg; 174 int len; 175 176 len = send(fd, ev->buf, ev->len, 0); //直接将数据 回写给客户端。未作处理 177 /* 178 printf("fd=%d\tev->buf=%s\ttev->len=%d\n", fd, ev->buf, ev->len); 179 printf("send len = %d\n", len); 180 */ 181 182 if (len > 0) { 183 184 printf("send[fd=%d], [%d]%s\n", fd, len, ev->buf); 185 eventdel(g_efd, ev); //从红黑树g_efd中移除 186 eventset(ev, fd, recvdata, ev); //将该fd的 回调函数改为 recvdata 187 eventadd(g_efd, EPOLLIN, ev); //从新添加到红黑树上, 设为监听读事件 188 189 } else { 190 close(ev->fd); //关闭链接 191 eventdel(g_efd, ev); //从红黑树g_efd中移除 192 printf("send[fd=%d] error %s\n", fd, strerror(errno)); 193 } 194 195 return ; 196 } 197 198 /*创建 socket, 初始化lfd */ 199 200 void initlistensocket(int efd, short port) 201 { 202 int lfd = socket(AF_INET, SOCK_STREAM, 0); 203 fcntl(lfd, F_SETFL, O_NONBLOCK); //将socket设为非阻塞 204 205 /* void eventset(struct myevent_s *ev, int fd, void (*call_back)(int, int, void *), void *arg); */ 206 eventset(&g_events[MAX_EVENTS], lfd, acceptconn, &g_events[MAX_EVENTS]); 207 208 /* void eventadd(int efd, int events, struct myevent_s *ev) */ 209 eventadd(efd, EPOLLIN, &g_events[MAX_EVENTS]); 210 211 struct sockaddr_in sin; 212 memset(&sin, 0, sizeof(sin)); //bzero(&sin, sizeof(sin)) 213 sin.sin_family = AF_INET; 214 sin.sin_addr.s_addr = INADDR_ANY; 215 sin.sin_port = htons(port); 216 217 bind(lfd, (struct sockaddr *)&sin, sizeof(sin)); 218 219 listen(lfd, 20); 220 221 return ; 222 } 223 224 int main(int argc, char *argv[]) 225 { 226 unsigned short port = SERV_PORT; 227 228 if (argc == 2) 229 port = atoi(argv[1]); //使用用户指定端口.如未指定,用默认端口 230 231 g_efd = epoll_create(MAX_EVENTS+1); //创建红黑树,返回给全局 g_efd 232 if (g_efd <= 0) 233 printf("create efd in %s err %s\n", __func__, strerror(errno)); 234 235 initlistensocket(g_efd, port); //初始化监听socket 236 237 struct epoll_event events[MAX_EVENTS+1]; //保存已经满足就绪事件的文件描述符数组 238 printf("server running:port[%d]\n", port); 239 240 int checkpos = 0, i; 241 while (1) { 242 /* 超时验证,每次测试100个链接,不测试listenfd 当客户端60秒内没有和服务器通信,则关闭此客户端链接 */ 243 244 long now = time(NULL); //当前时间 245 for (i = 0; i < 100; i++, checkpos++) { //一次循环检测100个。 使用checkpos控制检测对象 246 if (checkpos == MAX_EVENTS) 247 checkpos = 0; 248 if (g_events[checkpos].status != 1) //不在红黑树 g_efd 上 249 continue; 250 251 long duration = now - g_events[checkpos].last_active; //客户端不活跃的时间 252 253 if (duration >= 60) { 254 close(g_events[checkpos].fd); //关闭与该客户端链接 255 printf("[fd=%d] timeout\n", g_events[checkpos].fd); 256 eventdel(g_efd, &g_events[checkpos]); //将该客户端 从红黑树 g_efd移除 257 } 258 } 259 260 /*监听红黑树g_efd, 将满足的事件的文件描述符加至events数组中, 1秒没有事件满足, 返回 0*/ 261 int nfd = epoll_wait(g_efd, events, MAX_EVENTS+1, 1000); 262 if (nfd < 0) { 263 printf("epoll_wait error, exit\n"); 264 break; 265 } 266 267 for (i = 0; i < nfd; i++) { 268 /*使用自定义结构体myevent_s类型指针, 接收 联合体data的void *ptr成员*/ 269 struct myevent_s *ev = (struct myevent_s *)events[i].data.ptr; 270 271 if ((events[i].events & EPOLLIN) && (ev->events & EPOLLIN)) { //读就绪事件 272 ev->call_back(ev->fd, events[i].events, ev->arg); 273 } 274 if ((events[i].events & EPOLLOUT) && (ev->events & EPOLLOUT)) { //写就绪事件 275 ev->call_back(ev->fd, events[i].events, ev->arg); 276 } 277 } 278 } 279 280 /* 退出前释放所有资源 */ 281 return 0; 282 }
》分析了
(1)epoll反应堆模型recvdata函数
(2)epoll反应堆模型senddata函数
(3)epoll反应堆模型事件操作流程
(4)epoll反应堆模型节点事件检测:长时间不工作的结点,删除
三、libevent
1、libevent的安装和测试
》练习:源码安装
libevent库下载:https://libevent.org/
将 libevent-2.1.8-stable.tar.gz 拷贝至Ubuntu某个目录中(如:Documents/libevent)
>tar zxvf libevent-2.1.8-stable.tar.gz
(如果删除包,rm libevent-2.1.8-stable -r)
>cd libevent-2.1.8-stable
>ls (查找看是否有configure)
>./configure
>ls (查找看是否有makefile)
>ll Makefile
>make
>sudo make install (以root权限拷贝数据到对应的目录)
(验证是否安装成功)
>ls (注意:在源码安装目录查看,是否有sample)
>cd sample
>ls
>vi hello-world.c (大概查看下代码,看下端口为9995,实际已经有编译好的,直接执行)
>./hello-world
(打开另一个终端,执行>./client 127.0.0.1 9995,查看原终端是否收到flushed answer,即能否通信)
》如果自己编译的代码,编译时候需要指定库
如:>gcc hello-world.c -o hello -levent
为什么是 levent? 在 >cd /usr/local/lib/ ;>ls -l libevent.so ;Linux下动态库的起名是libxxx.so;所以编译时加上 -lxxx
2、解决动态库找不到的问题
》问题截图:
》解决:
》注意:
1)第1条中如果源码安装的时候,指定了目录--prefix=/usr/xxxx,需要在指定的目录/usr/xxxx下查找find
2)第3条练习:(要以管理员权限修改保存)
3、event_base讲解
》使用套路:
》事件处理框架—event_base:
4、event_base相关的小函数
》查看event在Linux平台下支持的函数
>touch event_base_method_support.c
>vi event_base_method_support.c
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <stdlib.h> 4 #include <sys/types.h> 5 #include <sys/stat.h> 6 #include <string.h> 7 #include <event2/event.h> 8 9 int main(int argc, const char* argv[]) 10 { 11 //创建一个事件处理框架 event_base 12 struct event_base *base = NULL; 13 base = event_base_new(); 14 //打印支持后端-IO转接函数 15 const char** meths = event_get_supported_methods(); 16 for(int i = 0; meths[i] != NULL; ++i) 17 { 18 printf("%s\n", meths[i]); 19 } 20 21 //查看当前正在使用IO转接函数 22 printf("current = %s\n", event_base_get_method(base)); 23 24 pid_t pid = fork(); 25 if(pid == 0) 26 { 27 //在子进程中重新初始化 28 event_reinit(base); 29 } 30 31 //添加事件。。。 32 33 //事件循环 34 event_base_dispatch(base); 35 36 //释放 event_base 37 event_base_free(base); 38 39 40 return 0; 41 }
>gcc event_base_method_support.c -levent
>./a.out
(查看输出:epoll,poll,select;——其实这是Linux平台下支持的三个转接函数current = epoll;当前正在使用epoll)
5、event事件的创建
》事件的创建(一共两种,这是一种,是不带缓冲区的)--event:
6、消息循环
》事件循环:
》练习说明:
>vi event_base_method_support.c
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <stdlib.h> 4 #include <sys/types.h> 5 #include <sys/stat.h> 6 #include <string.h> 7 #include <event2/event.h> 8 9 int main(int argc, const char* argv[]) 10 { 11 //创建一个事件处理框架 event_base 12 struct event_base *base = NULL; 13 base = event_base_new(); 14 //打印支持后端-IO转接函数 15 const char** meths = event_get_supported_methods(); 16 for(int i = 0; meths[i] != NULL; ++i) 17 { 18 printf("%s\n", meths[i]); 19 } 20 21 //查看当前正在使用IO转接函数 22 printf("current = %s\n", event_base_get_method(base)); 23 24 pid_t pid = fork(); 25 if(pid == 0) 26 { 27 //在子进程中重新初始化 28 event_reinit(base); 29 } 30 31 //添加事件。。。 32 33 //事件循环 34 //有可能需要很长时间,有可能就是一个死循环 35 event_base_dispatch(base); 36 37 //释放 event_base 38 event_base_free(base); 39 40 41 return 0; 42 }
7、libevent内部事件的状态转换
》事件的状态转换:
8、使用event读管道
>touch read_fifo.c
>vi read_fifo.c
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <stdlib.h> 4 #include <sys/types.h> 5 #include <sys/stat.h> 6 #include <string.h> 7 #include <fcntl.h> 8 #include <event2/event.h> 9 10 // 对操作处理函数 11 void read_cb(evutil_socket_t fd, short what, void *arg) 12 { 13 // 读管道 14 char buf[1024] = {0}; 15 int len = read(fd, buf, sizeof(buf)); 16 printf("data len = %d, buf = %s\n", len, buf); 17 printf("read event: %s", what & EV_READ ? "Yes" : "No"); 18 } 19 20 21 // 读管道 22 int main(int argc, const char* argv[]) 23 { 24 unlink("myfifo");//如果存在myfifo,删除文件 25 //创建有名管道 26 mkfifo("myfifo", 0664); 27 28 // open file 29 int fd = open("myfifo", O_RDONLY | O_NONBLOCK); 30 if(fd == -1) 31 { 32 perror("open error"); 33 exit(1); 34 } 35 36 // 读管道 37 struct event_base* base = NULL; 38 base = event_base_new(); 39 40 // 创建事件 41 struct event* ev = NULL; 42 ev = event_new(base, fd, EV_READ | EV_PERSIST, read_cb, NULL); 43 44 // 添加事件 45 event_add(ev, NULL); 46 47 // 事件循环 48 event_base_dispatch(base); 49 50 // 释放资源 51 event_free(ev); 52 event_base_free(base); 53 close(fd); 54 55 return 0; 56 }
>gcc read_fifo.c -o read -levent
9、使用event写管道
>touch write_fifo.c
>vi write_fifo.c
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <stdlib.h> 4 #include <sys/types.h> 5 #include <sys/stat.h> 6 #include <string.h> 7 #include <fcntl.h> 8 #include <event2/event.h> 9 10 // 对操作处理函数 11 void write_cb(evutil_socket_t fd, short what, void *arg) 12 { 13 // write管道 14 char buf[1024] = {0}; 15 static int num = 0; 16 sprintf(buf, "hello, world == %d\n", num++);//格式化字符串到buf中 17 write(fd, buf, strlen(buf)+1);//写入管道 18 } 19 20 21 // 写管道 22 int main(int argc, const char* argv[]) 23 { 24 // open file 25 int fd = open("myfifo", O_WRONLY | O_NONBLOCK); 26 if(fd == -1) 27 { 28 perror("open error"); 29 exit(1); 30 } 31 32 // 写管道 33 struct event_base* base = NULL; 34 base = event_base_new(); 35 36 // 创建事件 37 struct event* ev = NULL; 38 // 检测的写缓冲区是否有空间写 39 ev = event_new(base, fd, EV_WRITE | EV_PERSIST, write_cb, NULL); 40 41 // 添加事件 42 event_add(ev, NULL); 43 44 // 事件循环 45 event_base_dispatch(base); 46 47 // 释放资源 48 event_free(ev); 49 event_base_free(base); 50 close(fd); 51 52 return 0; 53 }
>gcc write_fifo.c -o write -levent
>./read
(打开另一个终端,切换到这个目录下,ls可以看到myfifo管道文件被创建了,然后执行>./write,查看两个终端的执行情况)
》测试:更改为只处理一次:
>vi write_fifo.c
将写改为只写一次: ev = event_new(base, fd, EV_WRITE, write_cb, NULL);
>gcc write_fifo.c -o write -levent
>./read
(打开另一个终端,切换到这个目录下,ls可以看到myfifo管道文件被创建了,然后执行>./write,查看两个终端的执行情况)
10、bufferevent介绍
》带缓冲区的事件(一共两种,这是另一种,是带缓冲区的):bufferevent
11、bufferevent函数介绍
(1)bufferevent的创建和回调函数的设置(第1、3、4条)
(2)socket通信客户端连接服务器时用到的函数(第2条)
(3)bufferevent读写缓冲区是否可用的设置(第5、6条)
》参考手册(libevent参考手册(中文版).pdf)page53-bufferevent的选项标志:
12、evconnlistener链接监听器
(1)evconnlistener_new_bind函数(第1条)
(2)链接监听器对应的小函数(第2、3条)
》参考手册(libevent参考手册(中文版).pdf)page99-100-evconnlistener_new()函数的flag的选项标志:
13、bufferevent实现服务器端代码
>mkdir bufferevent
>cd bufferevent
>touch server.c
>vi server.c
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <stdlib.h> 4 #include <sys/types.h> 5 #include <sys/stat.h> 6 #include <string.h> 7 #include <event2/event.h> 8 #include <event2/listener.h>//使用链接监听器evconnlistener_new_bind 9 #include <event2/bufferevent.h>//用到带缓冲区的事件bufferevent 10 11 // 读缓冲区回调 12 void read_cb(struct bufferevent *bev, void *arg) 13 { 14 char buf[1024] = {0}; 15 bufferevent_read(bev, buf, sizeof(buf)); 16 printf("recv buf: %s\n", buf); 17 18 char* p = "我已经收到了你发送的数据!"; 19 //printf("client say: %s\n", p); 20 21 // 发数据给客户端 - 往缓冲区中写数据 22 bufferevent_write(bev, p, strlen(p)+1); 23 //printf("====== send buf: %s\n", p); 24 printf("我发送了数据,给客户端...\n"); 25 } 26 27 // 写缓冲区回调 28 void write_cb(struct bufferevent *bev, void *arg) 29 { 30 //printf("我是写缓冲区的回调函数...\n"); 31 printf("发送的数据已经被发送出去了...\n"); 32 } 33 34 // 事件回调 35 void event_cb(struct bufferevent *bev, short events, void *arg) 36 { 37 if (events & BEV_EVENT_EOF) 38 { 39 printf("connection closed\n"); 40 } 41 else if(events & BEV_EVENT_ERROR) 42 { 43 printf("some other error\n"); 44 } 45 //释放 bufferevent 资源 46 bufferevent_free(bev); 47 printf("buffevent 资源已经被释放...\n"); 48 } 49 50 51 //连接完成之后,对应通信操作 52 void cb_listener( 53 struct evconnlistener *listener, 54 evutil_socket_t fd, 55 struct sockaddr *addr, 56 int len, void *ptr) 57 { 58 printf("connect new client\n"); 59 //得到传进来的 event_base 60 struct event_base* base = (struct event_base*)ptr; 61 //先接收数据 - 发送数据 62 //将fd 封装为 bufferevent 63 // 通信操作 64 // 添加新事件 65 struct bufferevent *bev = NULL; 66 bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE); 67 68 // 给bufferevent对应的读写缓冲区设置回调函数 69 bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL); 70 //设置读写缓冲区的回调函数可用,默认写是可用的 71 bufferevent_enable(bev, EV_READ); 72 } 73 74 75 int main(int argc, const char* argv[]) 76 { 77 78 // init server info 79 struct sockaddr_in serv; 80 memset(&serv, 0, sizeof(serv)); 81 serv.sin_family = AF_INET; 82 serv.sin_port = htons(9876); 83 serv.sin_addr.s_addr = htonl(INADDR_ANY);//对应0.0.0.0 84 85 //创建监听的事件处理框架 86 struct event_base* base; 87 base = event_base_new(); 88 // 创建监听的套接字 89 // 绑定 90 // 等待并接收连接请求 91 struct evconnlistener* listener = NULL; 92 //有新连接的时候,cb_listener会被调用 93 listener = evconnlistener_new_bind(base, cb_listener, base, 94 LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 95 -1, (struct sockaddr*)&serv, sizeof(serv)); 96 97 //开始事件循环 98 event_base_dispatch(base); 99 100 //释放资源 101 evconnlistener_free(listener); 102 event_base_free(base); 103 104 return 0; 105 }
>gcc server.c -o server -levent
>./server
(打开另一个终端,先把之前的客户端拷贝至bufferevent目录下,然后编译后运行./client 127.0.0.1 9876;然后发送数据,查看原server终端的接收情况)
》技巧扩展:代码片段
>cd ~/.vim
>mkdir UltiSnips
>touch c.snippets
>vi c.snippets
1 #================================= 2 #预处理 3 #================================= 4 #include "..." 5 snippet xINC 6 #include "${1:TODO}"${2} 7 endsnippet 8 # #include <...> 9 snippet xinc 10 #include <${1:TODO}>${2} 11 endsnippet 12 13 14 snippet xmyheader 15 #include <stdio.h> 16 #include <unistd.h> 17 #include <stdlib.h> 18 #include <sys/types.h> 19 #include <sys/stat.h> 20 #include <string.h> 21 ${1} 22 endsnippet 23 24 snippet xall 25 #include <stdio.h> 26 #include <unistd.h> 27 #include <stdlib.h> 28 #include <sys/types.h> 29 #include <sys/stat.h> 30 #include <string.h> 31 32 int main(int argc, const char* argv[]) 33 { 34 ${1} 35 return 0; 36 } 37 endsnippet 38 39 snippet xbuf 40 char ${1}[${2}] = {0}; 41 endsnippet 42 43 #sockaddr_in 44 snippet xsockaddr_in 45 struct sockaddr_in ${1} 46 endsnippet 47 48 # main 49 snippet xmain 50 int main(int argc, const char* argv[]) 51 { 52 ${0} 53 return 0; 54 } 55 endsnippet 56 57 # libevent event callback 58 snippet xeventcallback 59 void ${1}(evutil_socket_t fd, short what, void *arg) 60 { 61 ${2} 62 } 63 ${3} 64 endsnippet 65 66 # libevent bufferevent listen callback 67 snippet xlistencallback 68 void ${1}( 69 struct evconnlistener *listener, 70 evutil_socket_t fd, 71 struct sockaddr *addr, 72 int len, void *ptr) 73 { 74 ${2} 75 } 76 ${3} 77 endsnippet 78 79 # libevent read and write callback 80 snippet xbread_write_callback 81 void ${1}(struct bufferevent *bev, void *arg) 82 { 83 ${2} 84 } 85 ${3} 86 endsnippet 87 88 # libevent read and write callback 89 snippet xbevent_callback 90 void ${1}(struct bufferevent *bev, short events, void *arg) 91 { 92 if (events & BEV_EVENT_EOF) 93 { 94 printf("connection closed\n"); 95 } 96 else if(events & BEV_EVENT_ERROR) 97 { 98 printf("some other error\n"); 99 } 100 ${2} 101 } 102 ${3} 103 endsnippet 104 105 #main(void) 106 snippet xmainnon 107 int main(void) 108 { 109 ${0} 110 return 0; 111 } 112 endsnippet 113 114 # main args 115 snippet xargc 116 if(argc < ${1}) 117 { 118 printf("eg: ./a.out ${2}\n"); 119 exit(1); 120 } 121 ${3} 122 endsnippet 123 #xxx 124 snippet xxx 125 /* 126 * ${0} 127 */ 128 endsnippet 129 130 #ErrorPrint 131 snippet xerror 132 if(${1}== -1) 133 { 134 perror("${2} error"); 135 exit(1); 136 } 137 ${3} 138 endsnippet 139 140 #disconnect 141 snippet xclose 142 else if(${1} == 0) 143 { 144 printf("客户端已经断开了连接~~~~(>_<)~~~~\n"); 145 ${2} 146 } 147 ${3} 148 endsnippet 149 150 #ip and port information 151 snippet xipport 152 char ip[64] = {0}; 153 printf("New Client IP: %s, Port: %d\n", 154 inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, ip, sizeof(ip)), 155 ntohs(client_addr.sin_port)); 156 ${1} 157 endsnippet 158 #================================= 159 #结构语句 160 #================================= 161 # if 162 snippet if 163 if (${1:/* condition */}) 164 { 165 ${2:TODO} 166 } 167 endsnippet 168 # else if 169 snippet ei 170 else if (${1:/* condition */}) 171 { 172 ${2:TODO} 173 } 174 endsnippet 175 # else 176 snippet el 177 else 178 { 179 ${1:TODO} 180 } 181 endsnippet 182 # return 183 snippet re 184 return(${1:/* condition */}); 185 endsnippet 186 # Do While Loop 187 snippet do 188 do 189 { 190 ${2:TODO} 191 } while (${1:/* condition */}); 192 endsnippet 193 # While Loop 194 snippet wh 195 while (${1:/* condition */}) 196 { 197 ${2:TODO} 198 } 199 endsnippet 200 # switch 201 snippet sw 202 switch (${1:/* condition */}) 203 { 204 case ${2:c}: 205 { 206 } 207 break; 208 209 default: 210 { 211 } 212 break; 213 } 214 endsnippet 215 # 通过迭代器遍历容器(可读写) 216 snippet for 217 for (auto ${2:iter} = ${1:c}.begin(); ${3:$2} != $1.end(); ${4:++iter}) 218 { 219 ${5:TODO} 220 } 221 endsnippet 222 # 通过迭代器遍历容器(只读) 223 snippet cfor 224 for (auto ${2:citer} = ${1:c}.cbegin(); ${3:$2} != $1.cend(); ${4:++citer}) 225 { 226 ${5:TODO} 227 } 228 endsnippet 229 # 通过下标遍历容器 230 snippet For 231 for (decltype($1.size()) ${2:i} = 0; $2 != ${1}.size(); ${3:++}$2) 232 { 233 ${4:TODO} 234 } 235 endsnippet 236 # C++11风格for循环遍历(可读写) 237 snippet F 238 for (auto& e : ${1:c}) 239 { 240 } 241 endsnippet 242 # C++11风格for循环遍历(只读) 243 snippet CF 244 for (const auto& e : ${1:c}) 245 { 246 } 247 endsnippet 248 # For Loop 249 snippet FOR 250 for (unsigned ${2:i} = 0; $2 < ${1:count}; ${3:++}$2) 251 { 252 ${4:TODO} 253 } 254 endsnippet 255 # try-catch 256 snippet try 257 try { 258 } catch (${1:/* condition */}) { 259 } 260 endsnippet 261 snippet ca 262 catch (${1:/* condition */}) { 263 } 264 endsnippet 265 snippet throw 266 th (${1:/* condition */}); 267 endsnippet 268 #================================= 269 #容器 270 #================================= 271 # std::vector 272 snippet vec 273 vector<${1:char}> v${2}; 274 endsnippet 275 # std::list 276 snippet lst 277 list<${1:char}> l${2}; 278 endsnippet 279 # std::set 280 snippet set 281 set<${1:key}> s${2}; 282 endsnippet 283 # std::map 284 snippet map 285 map<${1:key}, ${2:value}> m${3}; 286 endsnippet 287 #================================= 288 #语言扩展 289 #================================= 290 # Class 291 snippet cl 292 class ${1:`Filename('$1_t', 'name')`} 293 { 294 public: 295 $1 (); 296 virtual ~$1 (); 297 298 private: 299 }; 300 endsnippet 301 #================================= 302 #结对符 303 #================================= 304 # 括号 bracket 305 snippet b "bracket" i 306 (${1})${2} 307 endsnippet 308 # 方括号 square bracket,设定为 st 而非 sb,避免与 b 冲突 309 snippet st "square bracket" i 310 [${1}]${2} 311 endsnippet 312 # 大括号 brace 313 snippet br "brace" i 314 { 315 ${1} 316 }${2} 317 endsnippet 318 # 单引号 single quote,设定为 se 而非 sq,避免与 q 冲突 319 snippet se "single quote" I 320 '${1}'${2} 321 endsnippet 322 # 双引号 quote 323 snippet q "quote" I 324 "${1}"${2} 325 endsnippet 326 # 指针符号 arrow 327 snippet ar "arrow" i 328 ->${1} 329 endsnippet 330 # dot 331 snippet d "dot" i 332 .${1} 333 endsnippet 334 # 作用域 scope 335 snippet s "scope" i 336 ::${1} 337 endsnippet 338 339 snippet xtcpcode 340 #include <stdio.h> 341 #include <unistd.h> 342 #include <stdlib.h> 343 #include <sys/types.h> 344 #include <string.h> 345 #include <sys/socket.h> 346 #include <arpa/inet.h> 347 #include <ctype.h> 348 349 350 int main(int argc, const char* argv[]) 351 { 352 if(argc < 2) 353 { 354 printf("eg: ./a.out port\n"); 355 exit(1); 356 } 357 struct sockaddr_in serv_addr; 358 socklen_t serv_len = sizeof(serv_addr); 359 int port = atoi(argv[1]); 360 361 // 创建套接字 362 int lfd = socket(AF_INET, SOCK_STREAM, 0); 363 // 初始化服务器 sockaddr_in 364 memset(&serv_addr, 0, serv_len); 365 serv_addr.sin_family = AF_INET; // 地址族 366 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 监听本机所有的IP 367 serv_addr.sin_port = htons(port); // 设置端口 368 // 绑定IP和端口 369 bind(lfd, (struct sockaddr*)&serv_addr, serv_len); 370 371 // 设置同时监听的最大个数 372 listen(lfd, 36); 373 printf("Start accept ......\n"); 374 375 struct sockaddr_in client_addr; 376 socklen_t cli_len = sizeof(client_addr); 377 while(1) 378 { 379 ${1} 380 } 381 382 close(lfd); 383 return 0; 384 } 385 endsnippet 386 387 snippet xclientcode 388 #include <stdio.h> 389 #include <sys/socket.h> 390 #include <unistd.h> 391 #include <stdlib.h> 392 #include <arpa/inet.h> 393 #include <string.h> 394 395 #define SERV_IP "127.0.0.1" 396 397 int main(int argc, char* argv[]) 398 { 399 if(argc < 2) 400 { 401 printf("./a.out servPort\n"); 402 exit(1); 403 } 404 // 端口 405 int port = strtol(argv[1], NULL, 10); 406 int cfd = socket(AF_INET, SOCK_STREAM, 0); 407 408 // 连接服务器 409 struct sockaddr_in serv_addr; 410 memset(&serv_addr, 0, sizeof(serv_addr)); 411 serv_addr.sin_family = AF_INET; 412 inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr); 413 serv_addr.sin_port = htons(port); 414 415 connect(cfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 416 417 // 接收数据 418 char buf[BUFSIZ]; 419 int len; 420 while(1) 421 { 422 printf("\n请输入要发送的数据: \n"); 423 // 从键盘接受输入 424 fgets(buf, sizeof(buf), stdin); 425 // 发送数据给服务器 426 write(cfd, buf, strlen(buf)); 427 428 // 接收服务器数据 429 len = read(cfd, buf, sizeof(buf)); 430 printf("接收到的数据:\n"); 431 write(STDOUT_FILENO, buf, len); 432 } 433 434 close(cfd); 435 return 0; 436 } 437 endsnippet
四、重要函数总结
在学习Linux高并发网络编程开发总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。
posted on 2020-07-09 17:50 Alliswell_WP 阅读(899) 评论(0) 编辑 收藏 举报