類分析
GCDAsyncSocket
狀態(tài)的枚舉
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;//當前類的狀態(tài)
uint16_t config;
uint16_t max4ReceiveSize;//最大接收數(shù)據(jù)包的大小
uint32_t max6ReceiveSize;
int socket4FD;//socket文件描述符
int socket6FD;
dispatch_queue_t socketQueue;//socket隊列
dispatch_source_t send4Source;//發(fā)送的source
dispatch_source_t send6Source;
dispatch_source_t receive4Source;
dispatch_source_t receive6Source;
dispatch_source_t sendTimer;//發(fā)送的定時器
GCDAsyncUdpSendPacket *currentSend;//當前發(fā)送的數(shù)據(jù)包
NSMutableArray *sendQueue;//發(fā)送隊列
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;//發(fā)送的數(shù)據(jù)
NSTimeInterval timeout;//超時的時間
long tag;//發(fā)送數(shù)據(jù)包的tag
BOOL resolveInProgress;//解決中
BOOL filterInProgress;//過濾中
NSArray *resolvedAddresses;//被解決的地址
NSError *resolveError;//解決出現(xiàn)的錯誤
NSData *address;//地址
int addressFamily;
發(fā)送數(shù)據(jù)
- (void)sendData:(NSData *)data toHost:(NSString *)host port:(uint16_t)port withTimeout:(NSTimeInterval)timeout tag:(long)tag;
這個方法中實例化了發(fā)送包趁蕊,并把host和port轉化為地址(參見getaddrinfo()函數(shù))
GCDAsyncSocket發(fā)送消息方法詳解
<>中的是方法名,有些方法名沒有寫全愁溜,所以配合代碼食用更佳熄驼。
<SendData>
創(chuàng)建GCDAsyncUdpSendPacket
host轉address
做檢查操作 <doPreSend>
把packet裝入sendQueue中
執(zhí)行出列操作 <maybeDequeueSend>
<maybeDequeueSend>
創(chuàng)建socket 執(zhí)行 <createSockets>
出列當前sendQueue中的packet并作為currentSend
特殊狀態(tài)處理GCDAsyncUdpSpecialPacket
錯誤處理
做預處理郭蕉,檢查包 執(zhí)行 <doPreSend>
<doPreSend>
有連接
如果currentSend正在進行其他操作,返回錯誤
如果沒有丁鹉,給currentSend賦值
無連接
packet進行其他操作妒潭,等待
遇上錯誤,返回
沒地址的處理
兩種連接最后總要給currentSend的address和addressFamily屬性賦值揣钦。
等待的處理:暫停 source
錯誤處理
Filter處理
沒有Filter情況直接執(zhí)行 <doSend>
<doSend>
有連接
發(fā)送方法為result=send()
無連接
發(fā)送方法為result=sendto() 參數(shù)中包含地址參數(shù)
根據(jù)result來判斷是否等待
錯誤處理是等待還是返回錯誤
等待情況的處理(沒有足夠空間)
當當前沒有不能接收數(shù)據(jù)的時候(kSock4CanAcceptBytes)說明有空間了杜耙,所以要重新開始source
設置超時相應
超時執(zhí)行 <maybeDequeueSend>
錯誤處理
正常情況
繼續(xù)從sendQueue中拿出packet來繼續(xù)搞事 執(zhí)行 <maybeDequeueSend>
<createSockets>
判斷IPv4|6是否可用
創(chuàng)建socket 執(zhí)行 <createSocket4>
<createSocket4>
創(chuàng)建socket的文件描述符
設置發(fā)送和接收source 執(zhí)行 <setupSendAndReceiveSourcesForSocket4>
<setupSendAndReceiveSourcesForSocket4>
創(chuàng)建source
設置event
send source
出錯處理
執(zhí)行 <suspendSend4Source>
無錯處理
執(zhí)行 <doSend>
receive source
出錯處理
無錯處理
執(zhí)行 <doReceive>
設置cancel
<doReceive>
通過flag判斷是否該暫停或者重啟receive source
計算是否該用IPv6|4拂盯;分有連接和無連接的情況
執(zhí)行socket IO佑女;使用result=recvfrom()函數(shù)接收數(shù)據(jù) 包括data
根據(jù)result判斷是否等待,錯誤處理,然后執(zhí)行代理方法通知接收到了數(shù)據(jù)谈竿。filter的操作团驱。
對等待和錯誤處理的值進行處理。
無錯處理
flag&kReceiveContinuous 繼續(xù)接收
接收一次 執(zhí)行 <doReceive>
例子:
一個packet過來
先進行地址轉換resolveInProgress = yes
進行轉換的時候空凸,同時進行出列操作嚎花,然后執(zhí)行doPreSend
doPreSend中resolveInProgress會導致source暫停
然后當?shù)刂忿D換進行完畢的時候,會再次調用doPreSend方法
這時候就會直接去調用doSend方法
調用sendto()方法
doPreSend的時候會因為currentSend正在干別的事情而暫停source
這個過程沒有講filter的相關內容呀洲。
預計理解dispatch_source/time的相關內容紊选。
c的函數(shù)庫的那些方法和結構體作為了解內容。
還有代碼組織方式道逗。