网络及安全iOS源码解析程序员

AsynSocket 源码解析之二

2017-01-10  本文已影响256人  upworld

CocoaAsyncSocket 源码学习摘要:

GCDAsynSocket 读取socket数据(接收对方发送过来的数据)调用:read(socketFD, buffer, (size_t)bytesToRead)。写入socket数据(向对方发送数据)调用 write(socketFD, buffer, (size_t)bytesToWrite)。一般调用read/write 方法的时候需要用result变量存储返回结果如:ssize_t result = read(socketFD, buffer, (size_t)bytesToRead);想知道result都有可能是什么值?
我们先简单看下read函数(write函数基本类似)说明:size_t read(int fd,void *buf,size_t nbyte)。read函数是负责从fd中读取内容。

想了解更多相关错误码,请参考:
[EAGAIN、EWOULDBLOCK、EINTR与非阻塞 长连接]
[IT牛人博客聚合]

所以在GCDAsynSocket源代码中我们经常看到下面代码或者类似代码(我加入了注释):


int socketFD = (socket4FD == SOCKET_NULL) ? socket6FD : socket4FD;//ipv4 or ipv6
//希望读取bytesToRead字节长度的数据到buffer缓存中。 
ssize_t result = read(socketFD, buffer, (size_t)bytesToRead);
LogVerbose(@"read from socket = %i", (int)result);

if (result < 0)//表示失败
{
    if (errno == EWOULDBLOCK)//异步IO需要处理(GCDAsynSocket用的是异步IO)
        //没有读到数据,下次可以继续读。设置waiting = YES
        //这种情况下后面可能就会调用resumeReadSource,继续监听socket。
        //当有数据可读的时候,继续尝试读取,具体原因后面会简单介绍。
        waiting = YES;
    else
        //后面会执行断开连接逻辑
        error = [self errnoErrorWithReason:@"Error in read() function"];
                
        socketFDBytesAvailable = 0;
}else if (result == 0)
{
    //读到socket末尾。遇到这种情况,后面会根据GCDSocket的kAllowHalfDuplexConnection设置做对应处理
    //如果kAllowHalfDuplexConnection = NO,后面会关闭socket
    //如果kAllowHalfDuplexConnection = Yes,后面会关闭读流操作(写流还可以进行),但不一定关闭socket。
    socketEOF = YES;
    socketFDBytesAvailable = 0;
}
else//表示soket数据读取成功
{
    bytesRead = result;//实际从socket获取到的字节数据
                
    if (socketFDBytesAvailable <= bytesRead)
        socketFDBytesAvailable = 0;//提供的数据都被读完了。
    else
        socketFDBytesAvailable -= bytesRead;
                
    if (socketFDBytesAvailable == 0)
    {
        //都是为了在一些复杂的情况下,防止sokect因为调用了suspendReadSource,导致不能继续工作。
        waiting = YES;  
    }
}

下面简单解释下result 返回不同值的时候GCDAsynSocket会做如何处理

下面简单解释下if (errno == EWOULDBLOCK)这句。
errno是系统库API。只有当一个库函数失败时,errno才会被设置。用来记录系统的最后一次错误代码。代码是一个int型的值,在errno.h中定义。errno详细解释

extern int * __error(void);
#define errno (*__error())

EWOULDBLOCK是一个什么鬼?

系统API 解释:
/* non-blocking and interrupt i/o */
#define EAGAIN      35      /* Resource temporarily unavailable */
#define EWOULDBLOCK EAGAIN      /* Operation would block */

什么情况下回返回 EWOULDBLOCK?

在Linux环境下开发经常会碰到很多错误(设置errno),其中EAGAIN是其中比较常见的一个错误(比如用在非阻塞操作中)。从字面上来看,是提示再试一次。这个错误经常出现在当应用程序进行一些非阻塞(non-blocking)操作(对文件或socket)的时候。例如,以 O_NONBLOCK的标志打开文件/socket/FIFO,如果你连续做read操作而没有数据可读。此时程序不会阻塞起来等待数据准备就绪返 回,read函数会返回一个错误EAGAIN,提示你的应用程序现在没有数据可读请稍后再试。

参考:
[EAGAIN、EWOULDBLOCK、EINTR与非阻塞 长连接]
[IT牛人博客聚合]

上一篇下一篇

猜你喜欢

热点阅读