读与写
读
- read:只能监控一个句柄
- select:一次性监控多个句柄是否可读/可写/异常,超时退出。
- 原理:所有句柄进入等待队列,只要有一个句柄的状态改变,立刻返回(进程从阻塞状态进入就绪),再遍历所有句柄,找到状态发生改变的句柄
- 文件句柄有限:1024个
- 文件句柄是最大值+1
- 超时时间必须每次都初始化(否则,这个时间是剩余的时间)
- 可以一次性不同类型的文件句柄,设备文件/socket/管道等等
- 内部使用轮询来检查状态是否改变
- poll:同select
- 区别:不是使用fd_set,而是使用链表,这样就没有句柄数量限制了
- epoll:和select类似
- 区别:
- 原理:所有句柄进入等待队列,只要有一个句柄的状态改变,把这个句柄放入eventpoll中的就绪队列(直接知道是哪个改变了,不用像select一样进行辩遍历)。进程再从阻塞状态进入就绪,再进行处理。进程处理完再进入eventpoll中的就绪队列继续阻塞。
- 水平触发:事件触发后,句柄就放在就绪队列,处理完了再放回等待队列
- 边缘触发:区别:没处理完也放回等待队列
写
多线程性能提升
- 多线程
- read到数据后,将数据处理放入线程中进行处理
- 使用线程池,从线程池中获取,再放回线程池,避免重复的创建与释放
- 再提提速:把read和write也放入线程中(虽然是读写缓存,但用户空间和内核空间的复制也是消耗一定时间),把这段时间空闲出来进行监控句柄的变化
- 锁
- 能不用锁就不用锁
- 注意锁的粒度,尽量小。原子锁(最小粒子)>互斥锁(unique_lock(自动加锁/解锁)>lock_guard>mutex)>读写锁(读写次数差异大)>自旋锁(实时性好)
- 信号量和条件变量
缓冲区
- 拆包
- 发送方缓冲区太小,一次发不完
- 接收方缓冲区太小,一次收不完
- 粘包
- 发送方缓冲区太大,发送太快
- 接收方缓冲区太大,没有及时读取
- 解决:定义消息边界,发送方发head+body,接收方根据head确定读几个字节
代码
int readDevice(char *buff, int buffSize)
{
int len, fs_sel;
fd_set fs_read;
struct timeval time;
if (fd <= 0 || NULL == buff)
{
return -1;
}
time.tv_sec = 1;
time.tv_usec = 0;
FD_ZERO(&fs_read);
FD_SET(fd, &fs_read);
fs_sel = select(fd + 1, &fs_read, NULL, NULL, &time);
if (fs_sel > 0)
{
len = read(fd, buff, buffSize);
printf("len = %d fs_sel = %d\n", len, fs_sel);
return len;
}
else
{
printf("can not read\n");
}
return len;
}
#include <sys/epoll.h>
int epid;
int max_value = 5;
struct epoll_event event;
struct epoll_event events[6];
int init_epoll(int fd)
{
epid = epoll_create(max_value);
event.events = EPOLLET | EPOLLIN | EPOLLONESHOT;
event.data.fd = fd;
if (epoll_ctl(epid, EPOLL_CTL_ADD, fd, &event) != 0)
{
printf("set epoll error!\n");
return 0;
}
printf("set epoll ok!\n");
return 1;
}
int readDevice2(char *buff, int buffSize)
{
int ret = 0;
int len = 0;
ret = epoll_wait(epid, events, max_value, 1000);
if (ret == 0)
{
return 0;
}
for (int i = 0; i < ret; i++)
{
if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN)))
{
printf("no data!\n");
break;
}
else if (events[i].events & EPOLLIN)
{
len = read(events[i].data.fd, buff, buffSize);
}
}
return len;
}