类分析
GCDAsyncSocket
状态的枚举
enum GCDAsyncUdpSocketFlags
{
kDidCreateSockets = 1 << 0, // If set, the sockets have been created.
kDidBind = 1 << 1, // If set, bind has been called.
kConnecting = 1 << 2, // If set, a connection attempt is in progress.
kDidConnect = 1 << 3, // If set, socket is connected.
kReceiveOnce = 1 << 4, // If set, one-at-a-time receive is enabled
kReceiveContinuous = 1 << 5, // If set, continuous receive is enabled
kIPv4Deactivated = 1 << 6, // If set, socket4 was closed due to bind or connect on IPv6.
kIPv6Deactivated = 1 << 7, // If set, socket6 was closed due to bind or connect on IPv4.
kSend4SourceSuspended = 1 << 8, // If set, send4Source is suspended.
kSend6SourceSuspended = 1 << 9, // If set, send6Source is suspended.
kReceive4SourceSuspended = 1 << 10, // If set, receive4Source is suspended.
kReceive6SourceSuspended = 1 << 11, // If set, receive6Source is suspended.
kSock4CanAcceptBytes = 1 << 12, // If set, we know socket4 can accept bytes. If unset, it's unknown.
kSock6CanAcceptBytes = 1 << 13, // If set, we know socket6 can accept bytes. If unset, it's unknown.
kForbidSendReceive = 1 << 14, // If set, no new send or receive operations are allowed to be queued.
kCloseAfterSends = 1 << 15, // If set, close as soon as no more sends are queued.
kFlipFlop = 1 << 16, // Used to alternate between IPv4 and IPv6 sockets.
#if TARGET_OS_IPHONE
kAddedStreamListener = 1 << 17, // If set, CFStreams have been added to listener thread
#endif
};
- Param
#if __has_feature(objc_arc_weak)
__weak id delegate;
#else
__unsafe_unretained id delegate;
#endif
dispatch_queue_t delegateQueue;
GCDAsyncUdpSocketReceiveFilterBlock receiveFilterBlock;
dispatch_queue_t receiveFilterQueue;
BOOL receiveFilterAsync;
GCDAsyncUdpSocketSendFilterBlock sendFilterBlock;
dispatch_queue_t sendFilterQueue;
BOOL sendFilterAsync;
uint32_t flags;//当前类的状态
uint16_t config;
uint16_t max4ReceiveSize;//最大接收数据包的大小
uint32_t max6ReceiveSize;
int socket4FD;//socket文件描述符
int socket6FD;
dispatch_queue_t socketQueue;//socket队列
dispatch_source_t send4Source;//发送的source
dispatch_source_t send6Source;
dispatch_source_t receive4Source;
dispatch_source_t receive6Source;
dispatch_source_t sendTimer;//发送的定时器
GCDAsyncUdpSendPacket *currentSend;//当前发送的数据包
NSMutableArray *sendQueue;//发送队列
unsigned long socket4FDBytesAvailable;//
unsigned long socket6FDBytesAvailable;
uint32_t pendingFilterOperations;
NSData *cachedLocalAddress4;
NSString *cachedLocalHost4;
uint16_t cachedLocalPort4;
NSData *cachedLocalAddress6;
NSString *cachedLocalHost6;
uint16_t cachedLocalPort6;
NSData *cachedConnectedAddress;
NSString *cachedConnectedHost;
uint16_t cachedConnectedPort;
int cachedConnectedFamily;
void *IsOnSocketQueueOrTargetQueueKey;//socketQueue的标识符
#if TARGET_OS_IPHONE
CFStreamClientContext streamContext;
CFReadStreamRef readStream4;
CFReadStreamRef readStream6;
CFWriteStreamRef writeStream4;
CFWriteStreamRef writeStream6;
#endif
id userData;
- GCDAsyncUdpSendPacket
NSData *buffer;//发送的数据
NSTimeInterval timeout;//超时的时间
long tag;//发送数据包的tag
BOOL resolveInProgress;//解决中
BOOL filterInProgress;//过滤中
NSArray *resolvedAddresses;//被解决的地址
NSError *resolveError;//解决出现的错误
NSData *address;//地址
int addressFamily;
发送数据
- (void)sendData:(NSData *)data toHost:(NSString *)host port:(uint16_t)port withTimeout:(NSTimeInterval)timeout tag:(long)tag;
这个方法中实例化了发送包,并把host和port转化为地址(参见getaddrinfo()函数)
GCDAsyncSocket发送消息方法详解
<>中的是方法名,有些方法名没有写全,所以配合代码食用更佳。
<SendData>
创建GCDAsyncUdpSendPacket
host转address
做检查操作 <doPreSend>
把packet装入sendQueue中
执行出列操作 <maybeDequeueSend>
<maybeDequeueSend>
创建socket 执行 <createSockets>
出列当前sendQueue中的packet并作为currentSend
特殊状态处理GCDAsyncUdpSpecialPacket
错误处理
做预处理,检查包 执行 <doPreSend>
<doPreSend>
有连接
如果currentSend正在进行其他操作,返回错误
如果没有,给currentSend赋值
无连接
packet进行其他操作,等待
遇上错误,返回
没地址的处理
两种连接最后总要给currentSend的address和addressFamily属性赋值。
等待的处理:暂停 source
错误处理
Filter处理
没有Filter情况直接执行 <doSend>
<doSend>
有连接
发送方法为result=send()
无连接
发送方法为result=sendto() 参数中包含地址参数
根据result来判断是否等待
错误处理是等待还是返回错误
等待情况的处理(没有足够空间)
当当前没有不能接收数据的时候(kSock4CanAcceptBytes)说明有空间了,所以要重新开始source
设置超时相应
超时执行 <maybeDequeueSend>
错误处理
正常情况
继续从sendQueue中拿出packet来继续搞事 执行 <maybeDequeueSend>
<createSockets>
判断IPv4|6是否可用
创建socket 执行 <createSocket4>
<createSocket4>
创建socket的文件描述符
设置发送和接收source 执行 <setupSendAndReceiveSourcesForSocket4>
<setupSendAndReceiveSourcesForSocket4>
创建source
设置event
send source
出错处理
执行 <suspendSend4Source>
无错处理
执行 <doSend>
receive source
出错处理
无错处理
执行 <doReceive>
设置cancel
<doReceive>
通过flag判断是否该暂停或者重启receive source
计算是否该用IPv6|4;分有连接和无连接的情况
执行socket IO;使用result=recvfrom()函数接收数据 包括data
根据result判断是否等待,错误处理,然后执行代理方法通知接收到了数据。filter的操作。
对等待和错误处理的值进行处理。
无错处理
flag&kReceiveContinuous 继续接收
接收一次 执行 <doReceive>
例子:
一个packet过来
先进行地址转换resolveInProgress = yes
进行转换的时候,同时进行出列操作,然后执行doPreSend
doPreSend中resolveInProgress会导致source暂停
然后当地址转换进行完毕的时候,会再次调用doPreSend方法
这时候就会直接去调用doSend方法
调用sendto()方法
doPreSend的时候会因为currentSend正在干别的事情而暂停source
这个过程没有讲filter的相关内容。
预计理解dispatch_source/time的相关内容。
c的函数库的那些方法和结构体作为了解内容。
还有代码组织方式。