標籤:http伺服器 高並發 oc 多線程 socket編程
在上一篇文章《iOS從零開始學習socket編程——HTTP1.0伺服器端》中我們已經簡單的接觸了OC搭建的HTTP伺服器。
(地址http://blog.csdn.net/abc649395594/article/details/45131373)
出於使用者體驗和魯棒性考慮,這裡把這個HTTP伺服器改進成多線程的。
首先,AnsycSocket這個類是基於OC的Runloop實現的,Runloop實現了方法的非同步呼叫但並不支援多線程。
在這裡首先簡單區分一下多線程和方法非同步呼叫的區別。他們都可以避免線程的阻塞,只不過多線程是新開一個線程處理任務,處理完成之後通知主線程;而方法非同步呼叫本質上還是在主線程裡調用方法,只不過主線程並不會阻塞著等待方法的執行結果,而是繼續執行原有的任務,直到方法執行完成之後才進行相應的處理。從某種意義上來說,socket編程並不總需要伺服器支援多線程,因為新增一個線程本身也會增加CPU的負擔,而他們的執行效果也基本類似。
然而,考慮一下這種情況,我們就應該發現多線程也有他必不可少的理由:假設使用者上傳一張圖片並且請求對這個圖片進行處理,假設圖片的處理非常複雜並且涉及到大量計算,此時如果任然在主線程中執行處理圖片的方法,系統的執行效率會大幅度下降,使用者體驗變差。如果新增一個線程,那麼多核處理器的處理優勢將會被充分發揮,大大提高使用者體驗。
因此總結起來就是:我們並不需要為每一個新的socket串連新增一個線程,確應該在處理資料的時候,充分發揮多核處理器的優勢,新增線程,提高執行速度。
也正因為如此,AnsycSocket本身的回呼函數是非同步呼叫,並不支援多線程,如果在子線程中調用AnsycSocket類對象的writeData方法(向socket中寫入資料)將不會起任何作用。解決方案是,將資料的處理放在新的線程,並在主線程中執行writeData方法和UI相關的改變。
重點需要修改的函數是didReadData方法:
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{ //處理資料}
我們只用將這個方法進行簡單地修改就可以支援多執行緒資料。
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{ __block AsyncSocket *localSocket = sock; __block NSData *localData = data; dispatch_async(dispatch_get_global_queue(0, 0), ^{ NSLog(@"thread = %@",[NSThread currentThread]); [self dealWithData:localSocket Data:localData]; });}
這裡建立了三個block類型的對象避免在block中出現循環參考的問題。
接下來實現dealWithData方法:
- (void)dealWithData:(AsyncSocket *)sock Data:(NSData *)data{ //這個方法和AnsycSocket的didReadData方法極為類似 /* 處理相關資料 */ dispatch_async(dispatch_get_main_queue(), ^{ [sock writeData:data withTimeout:-1 tag:ECHO_MSG]; [sock disconnectAfterWriting]; });}
可以看出,只是簡單的新增了一個線程並且把原來需要在didReadData方法中實現的內容搬到了自訂的函數中。處理完成資料後,記得在主線程中寫入資料即可。
PS:didReadData可能會出現無法擷取資料或多次擷取資料的問題。處理方法見我的另一篇部落格《AsyncSocket didReadData函數詳解》
地址:http://blog.csdn.net/abc649395594/article/details/45046871
最後嘮叨一句:OC並不適合做服務區開發,這裡寫了很多隻是為了加深對Socket編程本質的理解。
iOS從零開始學習socket編程——高並發多線程伺服器