socket長連線所用到的八大技術

2021-08-19 23:58:49 字數 2919 閱讀 1582

不過socket相關的原形在我那篇socket通訊中有介紹。

用到8大技術:

第一大技術是:多執行緒,超簡單,一句而已(dispatch_async(dispatch_get_global_queue(dispatch_queue_priority_default, 0), ^);。但是有多執行緒引起的崩潰問題,只有用共享鎖解決了和socket整合定時器的功能來處理超時問題才得到解決。所以多執行緒起來容易,使用不好就是一大堆崩潰問題。多執行緒要慎用,能不用盡量就盡量不用。必定程式是順序執行的,多執行緒是為了解決不阻礙主線程才必須用,若只是為了提高執行效率,就要多考慮考慮了,因為用不好效率沒有提高,他還老嗝屁。

第二大技術:socket和select。作為非同步socket他們本來就是一對。用 server_sock_fd = socket(af_inet, sock_stream, 0);設定為非同步socket,用int i = connect(server_sock_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in));建立非同步socket,它通常在3秒內建立連線,然後用long ret = select(max_fd + 1, &read_fd_set, null, null, &tv);來監聽檔案描述符(專業名稱叫 fd)對應socket連線的可讀標誌,若服務端有訊息傳送過來,檔案描述符可讀,select函式會立即結束偵聽,若判斷為可讀(if (fd_isset(server_sock_fd, &read_fd_set)))就讀取緩衝區的資料(byte_num = recv(server_sock_fd,recv_msg,buffer_size,0);),若讀取的位元組數為0就說明socket已經斷鏈,需要關閉本地fd,立刻發起連線;若讀的位元組數為負數就是接受訊息錯誤。當然socket一旦建立,它的一般都可讀,除非出現網絡卡緩衝區滿了寫不進去才處於非可讀狀態,所以需要通過socket長連線寫資料時需要用判斷它是否可寫ret = select(server_sock_fd + 1, &read_fd_set, &client_fd_set, null, &tv);if (fd_isset(server_sock_fd, &read_fd_set))。利用select函式的超時功能當定時器來使用,解決訊息超時問題,不另分為一類技術了。詳細內容見我的文章《使用底層socket實現客戶端和服務端通訊,傳送請求》:

第三技術:管道。那有人問既然socket大部分處理可寫狀態,那為何不想傳送訊息不直接傳送就可以了?因為長連線可能斷鏈,雖然它可以立即發起連線,重新建立連線,那若你正在它連線時傳送訊息怎麼辦?還有若網絡卡緩衝區寫滿了,暫時傳送不出去訊息怎麼辦。所以用select來偵聽並且判斷可寫標誌才是王道。與伺服器之間建立了長連線後,這個長連線線程大部分時間處於偵聽fd的select函式(long ret = select(max_fd + 1, &read_fd_set, null, null, &tv);)處。當外部有訊息需要傳送時,如何立刻傳送呢?最傻的方法時採用輪詢的方法,就把超時時間(tv)設定的小一點來達到及時傳送的目的。cpu排程的情況有三種:執行緒結束,呼叫sleep(usleep)函式,呼叫呼叫wait函式掛起執行緒。所以不用擔心在乙個函式內部非以上三種情況時被其它非系統執行緒搶走cpu了。當然眾所周知乙個執行緒中的迴圈越快耗電越快,對主機的效能影響越大(畢竟乙個應用只使用乙個cpu,這個執行緒用到cpu時間越多,其它執行緒得到cpu的時間就越少,而且cpu處於休眠狀態的時間更少)。這就是輪詢方法和處理及時性之間的均衡問題。用管道技術就能很好的解決這個問題,脫離這個輪詢方法的桎梏,既解決了設定超時時間的足夠長,又能解決訊息的實時傳送。只需要把管道的讀標誌加入fd的讀集合,fd_set(readpipefd, &read_fd_set);當需要立即傳送訊息時,立刻向管道裡寫資料就可以,那麼select函式(long ret = select(max_fd + 1, &read_fd_set, null, null, &tv);)立刻結束等待,先別讀管道訊息,然後監聽是否可以寫ret = select(server_sock_fd + 1, &read_fd_set, &client_fd_set, null, &tv);然後把管道訊息讀出來,把訊息傳送出去就可以。

第四大技術:block。block能夠實現傳送訊息和響應訊息的非同步問題,並且可以實現找到以前對應的訊息和響應訊息。最典型的時大所周知的afnetwork第三方庫。它能解決傳送函式找到自己對應的響應訊息。block方面的例子後續我會寫文章進一步說明。**方面的典型例子見我的文章《自己實現非同步傳送請求和》:

第五大技術:全域性共享鎖,nslock。由於用到多執行緒並且用到字典,所以必然要用到全域性共享鎖。不然主線程正訪問或拷貝乙個字典,另乙個執行緒把他的引用取消了,那麼你等著程式掛吧!arc機制是當乙個物件沒有乙個指標指向它時,它就可能被系能釋放,當系統正釋放的過程中你引用它,它暴跳如雷,把你的應用乾掉,並且崩潰棧沒有任何資訊留下,這就是你惹惱系統老大的後果,不給你任何交代乾掉你的應用。所以避免這種記憶體釋放的問題,最好的是若只是乙個基本變數如:int直接定義為對應基本變數型別就可以,別玩物件指標玩上癮了,被殺到就不知道。當然的你的資料量很大很關鍵非要用字典等物件時,你只有靠nslock這個來把大鎖先鎖住它,等你用完了在放開它。

第六大技術:單例。這個物件導向程式設計經常考試的問題。實現長連線需抽象出一定的block介面函式和全域性變數。你若都定義為靜態全域性變數和靜態全域性函式,那樣封裝性不好,誰想怎麼玩怎麼玩,很不好。還是單例好,全域性只有乙個例項,並且把全域性的變數都通過全域性函式呼叫,避免暴露全域性變數。

第七大技術:狀態機。既然是長連線,長連線就有初始化,連線中,連線成功,連線異常,連線超時等狀態,相應也需要狀態機記錄它的狀態。狀態機就是用全域性變數記錄連線在不同情況的列舉值,在不同的場景下根據變數不同的列舉值來做出對應的處理。

第八大技術:訊息佇列。長連線的訊息佇列分為傳送訊息佇列,待處理訊息佇列(訊息已經傳送出去需要等待相應的訊息),響應訊息佇列(一次性把響應訊息收過來,等待處理訊息函式統一處理)。我是利用select函式的超時功能來當定時器來使用,每個訊息對應乙個字典,傳送訊息和待處理訊息有傳送出去時的時間記錄,響應訊息與收到訊息的時間理論。當前時間減去他們的時間大於超時時間就進行訊息超時處理。

Socket長連線和短連線的區別

短連線連線 傳輸資料 關閉連線 http是無狀態的,瀏覽器和伺服器每進行一次http操作,就建立一次連線,但任務結束後就中斷連線。短連線是指socket連線後傳送後接收完資料後馬上斷開連線。長連線連線 傳輸資料 保持連線 傳輸資料 關閉連線 長連線指建立socket連線後不管是否使用都保持連線,但安...

八大演算法的user story

2014.6.30 好久沒有程式設計了,連個冒泡都不會了。勉勉強強編了乙個沒有flag的,明天考慮加個flag。連編譯都不會了,起碼搞了15分鐘,b汗!今天用securecrt來遠端登入自己的虛擬機器了,高階!終於在自己的機子實現小黑窗了!2014.7.1 今天來學校學程式設計,看了大綠書後,終於搞...

Redis的八大應用

快取 key val快取 分布式鎖 利用redis的setnx功能來編寫分布式的鎖,如果設定返回1說明獲取鎖成功,否則獲取鎖失敗 計數器 incr命令來實現計數器功能,記憶體操作,效能非常好 佇列 可以利用redis的訂閱 發布功能實現乙個簡單的訊息佇列 排行榜 可以利用有序集合來實現 分布式會話 ...