服務器需要解決的如下問題:
(1)如何檢測有新客戶端連接尔邓? 答: IO復用的select、poll锉矢、epoll等socket API
? ? ? ? 首先關于IO復用機制的比較梯嗽,目前windows系統(tǒng)支持select、WSAAsyncSelect沽损、WSAEventSelect灯节、完成端口(IOCP),linux系統(tǒng)支持select绵估、poll炎疆、epoll。
? ? ? ? 1. select和poll? :主動定時輪詢是否有可讀可寫事件国裳,效率不高形入;
? ? ? ? 2.WSAAsyncSelect、WSAEventSelect缝左、完成端口(IOCP)亿遂、epoll:被動異步事件通知,減少無效時間渺杉,WSAAsyncSelect是利用windows消息隊列的事件機制來通知我們設定的窗口過程函
數崩掘,IOCP是利用GetQueuedCompletionStatus返回正確的狀態(tài),epoll是epoll_wait函數返回少办。比如connect函數連接另外一端,如果連接socket是異步的诵原,那么connect雖然不能立刻連接完成英妓,但是也是
會立刻返回,無需等待绍赛,等連接完成之后蔓纠,WSAAsyncSelect會返回FD_CONNECT事件告訴我們連接成功,epoll會產生EPOLLOUT事件吗蚌,我們也能知道連接完成腿倚。甚至socket有數據可讀時
WSAAsyncSelect產生FD_READ事件,epoll產生EPOLLIN事件蚯妇,等等敷燎。
(2)如何接受客戶端連接暂筝??答:socket API的accept函數
? ? ? ? 默認accept函數會阻塞在那里,如果epoll檢測到偵聽socket上有EPOLLIN事件硬贯,或者WSAAsyncSelect檢測到有FD_ACCEPT事件焕襟,那么就表明此時有新連接到來,這個時候調用accept函數饭豹,就不
會阻塞了鸵赖。當然產生的新socket你應該也設置成非阻塞的。這樣就能在新socket上收發(fā)數據了拄衰。
(3)如何檢測客戶端是否有數據發(fā)來它褪?答:如上(1)中注冊的IO復用機制是否有可寫事件
(4)如何收取客戶端發(fā)來的數據??答:收取客戶端數據用recv函數翘悉,socket上有可讀事件的時候才去收取數據,這樣調用recv或者read函數時不用等待镐确,對于非阻塞的socket包吝,如果無數據recv或者
read函數會立即返回,錯誤碼為EWOULDBLOCK源葫。
(5)如何檢測連接異常诗越?答:當服務器收到異常事件EPOLLERR或者關閉事件FD_CLOSE,可以關閉socket息堂,此外嚷狞,recv或者read返回0時也可以關閉socket
(6)如何給客戶端發(fā)送數據?給客戶端發(fā)送數據用send函數 服務器不需要時刻偵聽可寫事件荣堰,只是在需要有數據要發(fā)送床未,則先嘗試著去發(fā)送,如果發(fā)送不了或者只發(fā)送出去部分振坚,剩下需要將其緩存起
來薇搁,然后設置檢測該socket上可寫事件,下次可寫事件產生時渡八,再繼續(xù)發(fā)送啃洋,如果還是不能完全發(fā)出去,則繼續(xù)設置偵聽可寫事件屎鳍,如此往復宏娄,一直到所有數據都發(fā)出去為止。一旦所有數據都發(fā)出去以
后逮壁,服務器要移除偵聽可寫事件孵坚,避免無用的可寫事件通知。
(7)如何在給客戶端發(fā)完數據后關閉連接?連接關閉分為主動關閉和被動關閉卖宠,被動關閉是服務器檢測到客戶端異澄¤荆或者關閉事件、recv和send立即返回0時被迫關閉連接逗堵;主動關閉是動調用
close/closesocket來關閉連接秉氧,比如客戶端發(fā)送非法的數據,比如一些網絡攻擊的嘗試性數據包蜒秤。
(8)收發(fā)緩沖區(qū)如何設定汁咏?緩沖可以像string、vector一樣作媚,設計出一個可以動態(tài)增長的緩沖區(qū)攘滩,按需分配,不夠還可以擴展纸泡。
(9)協(xié)議的設計要點:像TCP/IP協(xié)議基于字節(jié)的流式數據漂问,需要界定包的大小已經包的界限,比如固定包的大小女揭,使用\r\n作為包結束符蚤假,并且為了節(jié)省網絡帶寬和加快數據處理,盡可能使包的長度
比較小吧兔。
(10)服務器程序結構的組織:主流的思想是one thread one loop的策略磷仰,設定一些線程在一個循環(huán)里面做網絡通信相關的事情,另外設定一些線程去處理接收到的數據境蔼,并解包處理業(yè)務邏輯灶平。如果
多線程設定無法提高提高程序性能,浪費CPU時間片進行上下文切換箍土,可以將網絡線程與業(yè)務邏輯線程合并逢享。