异步Socket(非阻塞模式)的应用

异步Socket(非阻塞模式)的应用


若Socket是同步模式(即阻塞模式):
1. send(1024)需要等1024个字节发完了才会返回(或者socket被关闭了)。这使得server在和低速的client通信时被阻塞,所以高性能server要使用非阻塞方式。
2. recv(1024)不会等1024个字节,但必须要有数据才行,否则会被阻塞。所以阻塞的recv通常需要判断是否有数据。


将socket设为nonblocking的:
    int SetNoneBlocking(int fd){
        int flag = 1;
        if(ioctl(fd, FIONBIO, &flag) == -1){
            return -1;
        }
        return 0;
    }
这样在send和recv都不会阻塞。
recv时,若缓冲区没有数据,则返回-1,errno会被设为EAGAIN或EWOULDBLOCK。
send时,若缓冲区满(client还没有消耗完),则返回的值比发送的值少,errno同样会被设置为EAGAIN或EWOULDBLOCK。


使用epoll异步服务client的典型场景:
1. epoll发现listen的fd有client,使用accept接受client。
2. 将client fd设为非阻塞模式。
3. 将client fd加到epoll中,只侦听读事件(有数据时激发事件)(写事件由写时第5步侦听)。
4. epoll wait等待事件到来。


读非阻塞socket的典型场景:
1. epoll_wait返回,获取事件,若事件是client fd的读事件,则进行下面步骤。
2. 从client fd读取数据。
3. 若读取返回错误,关闭client。
4. 若读取返回没有数据(errno为EAGAIN或EWOULDBLOCK),返回ReadPartial自定义错误(只读了一部分)。
5. 若读取成功,解析数据。若解析数据不够,跳到第2步。


写非阻塞socket的典型场景:
1. 假设要发送的包都放在队列,并且有定时器知道何时应该发包(将下一次时间差作为epoll_wait的timeout参数)
2. 从epoll_wait返回,由以下情况:
    有client的写事件(缓冲区已空,可以写入,由第5步设置):执行3-6之后(写入完毕),去掉写事件侦听。
    检查定时器,有需要主动写入的数据:将数据放入队列,若当前不是WritePartial(缓冲区满了),则执行3-6。
3. 将数据写入client_fd。
4. 若写入错误,关闭client。
5. 若写入部分数据(errno为EAGAIN或EWOULDBLOCK)且返回的值比写入小:
    将已写入的数据从队列删除
    侦听client fd的写事件(缓冲区现在满了,等空的时候告诉我,我继续写)
    返回WritePartial自定义错误(只写了一部分)。
6. 若写入成功,从队列删除整个包。

你可能感兴趣的:(异步Socket(非阻塞模式)的应用)