Unix/Linux编程:网络编程封装总结
发布日期:2022-03-16 03:25:39
浏览次数:34
分类:技术文章
本文共 3157 字,大约阅读时间需要 10 分钟。
网络编程原则
明确:网络IO的职责
也就是说,封装是可以从两个层面来封装,一个是从操作IO的层面,比如各种接收、发送数据格式,监听数据流等,一个是从检测IO层面,也叫做事件引擎,专门用来检测IO事件。比如redis的封装层面如下:
ps,是在【IO操作层】解决的:- 所谓粘包,就是多个包可能合并成一个包发送,需要分开了
- 解决的关键在于想办法从收到的数据报中将包与包之间的边界区分出来,主要有三种方法:
- 只发送固定包长度的数据报
- 以指定字符(串)为包的结束标记
- 包头+包体格式:包头是固定大小的,而且包头中必须含有一个字段来说明接下来的包体有多大。
关注:网络编程需要解决的四个问题
连接的建立
作为服务端,主要扮演两种角色:
- 接收他人请求的连接
- 服务端作为客户端去连接他人
连接的断开
分为主动断开和被动断开
消息的接收
消息的发送
关于epoll
结构以及接口
struct eventpoll { // ... struct rb_root rbr; // 管理 epoll 监听的事件 struct list_head rdllist; // 保存着 epoll_wait 返回满⾜条件的事件 // ...};struct epitem { // ... struct rb_node rbn; // 红⿊树节点 struct list_head rdllist; // 双向链表节点 struct epoll_filefd ffd; // 事件句柄信息 struct eventpoll *ep; // 指向所属的eventpoll对象 struct epoll_event event; // 注册的事件类型 // ...};struct epoll_event { __uint32_t events; // epollin epollout epollel(边缘触发) epoll_data_t data; // 保存 关联数据};typedef union epoll_data { void *ptr; int fd; uint32_t u32; uint64_t u64;}epoll_data_t;int epoll_create(int size);/**op: EPOLL_CTL_ADD EPOLL_CTL_MOD EPOLL_CTL_DELevent.events: EPOLLIN 注册读事件 EPOLLOUT 注册写事件 EPOLLET 注册边缘触发模式,默认是水平触发*/int epoll_ctl(int epfd, int op, int fd, struct epoll_event* event);/**events[i].events: EPOLLIN 触发读事件 EPOLLOUT 触发写事件 EPOLLERR 连接发生错误 EPOLLRDHUP 连接读端关闭 EPOLLHUP 连接双端关闭*/int epoll_wait(int epfd, struct epoll_event* events, int maxevents, inttimeout);
- 调用epoll_create会创建一个epoll对象
- 调用epoll_ctl添加到epoll中的事件都会与网卡驱动程序建立回调关系,相关事件触发时会调用回调函数 ( ep_poll_callback ),将触发的事件拷贝到rdlist双向链表中
- 调用epoll_wait会将rdlist中就绪事件拷贝到用户态中
epoll编程
连接建立
(1)处理客户端的连接
// 1. 注册监听listenfd的读事件struct epoll_event ev;ev.events |= EPOLLIN;epoll_ctl(efd, EPOLL_CTL_ADD, listenfd, &ev);// 2. 当触发listenfd的读事件时,回调函数中需要调用accept接收新的连接int clientfd = accept(listenfd, addr, sz);struct epoll_event ev;ev.events |= EPOLLIN;epoll_ctl(efd, EPOLL_CTL_ADD, clientfd, &ev);
(2)去连接第三方服务
// 1. 创建 socket 建立连接int connectfd = socket(AF_INET, SOCK_STREAM, 0);connect(connectfd, (struct sockaddr *)&addr, sizeof(addr));//2. 等待connectfd连接成功(当可写时,也就是可以发送ACK时就表示连接成功了)struct epoll_event ev;ev.events |= EPOLLOUT;epoll_ctl(efd, EPOLL_CTL_ADD, connectfd, &ev);//3. 当connectfd写事件被触发,连接建立成功if (status == e_connecting && e->events & EPOLLOUT) { status == e_connected; // 这里需要把写事件关闭 epoll_ctl(epfd, EPOLL_CTL_DEL, connectfd, NULL);}
连接断开
if (e->events & EPOLLRDHUP) { // 读端关闭 close_read(fd); close(fd);}if (e->events & EPOLLHUP) { // 读写端都关闭 close(fd);}
数据到达
// reactor 要用非阻塞ioif (e->events & EPOLLIN) { //数据到达时也就是发生了EPOLLIN事件,这时就可以读取数据了 while (1) { //一直读,直到读取完毕或者读取出错 int n = read(fd, buf, sz); if (n < 0) { if (errno == EINTR) continue; if (errno == EWOULDBLOCK) //缓冲区中的数据都已经读完了 break; close(fd); //读取出错,关闭专线 } else if (n == 0) { close_read(fd); // close(fd); } // 业务逻辑 }}
服务端数据发送给对端
int n = write(fd, buf, dz);if (n == -1) { if (errno == EINTR) continue; if (errno == EWOULDBLOCK) { //缓冲区已经满了 struct epoll_event ev; ev.events = EPOLLOUT; epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev); } close(fd);}// ...if (e->events & EPOLLOUT) { int n = write(fd, buf, sz); //... if (n > 0) { epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL); }}
reactor应用
单 reactor
多 reactor (one eventloop per thread)
多线程
多进程
转载地址:https://blog.csdn.net/zhizhengguan/article/details/122944857 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
初次前来,多多关照!
[***.217.46.12]2024年04月06日 13时20分41秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
选择排序
2019-04-27
PHP session回收机制
2019-04-27
最新的全球编程语言,操作系统,web服务器等使用率分析报告
2019-04-27
用C语言写PHP扩展
2019-04-27
PHP Extension programming
2019-04-27
海量数据处理
2019-04-27
PHP防止注入攻击
2019-04-27
多路IO复用模型 select epoll 等
2019-04-27
Linux Epoll介绍和程序实例
2019-04-27
output_buffering详细介绍
2019-04-27
php缓冲 output_buffering和ob_start
2019-04-27
php error_reporting 详解
2019-04-27
剖析PHP中的输出缓冲
2019-04-27
HTTP响应头不缓存
2019-04-27
PHP安装扩展mcrypt以及相关依赖项 【PHP安装PECL扩展的方法】
2019-04-27
Javascript到PHP加密通讯的简单实现
2019-04-27
德国SNS交友/视频网站Poppen.de的技术架构分享
2019-04-27
UNIX环境编程
2019-04-27
一笔画问题【数据结构-图论】
2019-04-27
红黑树
2019-04-27