云计算 wordpress Python linux Firefox 微软 编程 mysql shell apache 开源 Ubuntu google nginx Android Windows php centos java 程序员

面向连接的echo服务编程实例

  在linix使用socket進行網絡編程,並且在文中給出相應的程序和說明,以使大家對socket編程有初步的了解。現在我們解決文中出現的問題:不能同時與多個客戶進行通信,只能第一個客戶通信結束事才能與第二個客戶進行通信,依次...直到有的客戶連接超時,或者沒有客戶進行連接。通常一個服務器程序應能同時與多個客戶端進行通信,能及時對它的請求作出回復。
  其實這個問題有很多解方案,最明顯的一種就是采用多線程或者采用多進程。顯然多進程是不可取的,因此有多線程的存。采用多線程技術時,每當有客戶請求連接,服務器都是新建一個線程與之通信,通信完成後將終止該線程。這樣的情況適合於大量IO操作的服務器程程,或者服務器的是多核的。否則,這樣未免太浪費了,系統的開銷也會很大。因此我們致力於采用單進程單線的解決方案。
  其實,我們對C/S通信方式中的服務器端會有這樣的直覺:服務器等待客戶的到來,如果在一定的時間內(10ms),如果沒有收到請求,那就不等了,馬上回來處量已連接上的客戶端,並與之通信。與已連接上的客戶端進行通信,也采用這樣的方式,對於任一客戶端,看它有沒有數據到來,有則處理,沒則輪到下一個客戶,采用相同的處理方式。依次進行下去,就不需要使用多進程或多線程技術,可以如何實現呢?

  其實IO可以分為阻塞IO和非阻塞IO,當讀阻塞IO的數據時,直到有數據時才返回,否則一直阻塞;非阻塞IO卻不同,讀非阻塞IO的數據時,不管有沒有數據到來,它都會及時返回,有沒有數據到來依據返回值進行判斷。無論我們在代碼中使用open還是socket函數返回的文件描述符,它都是阻塞的,要使它變為非阻塞,則必須使用fcntl函數對它的屬性進行更改。

  fd為文件描述符,cmd表示命令,可變參數的個數和類型根據cmd值的不同而不同。

  當文件為非阻塞時,accept會回返回它接受連接的客戶端描述符,如沒有客戶請求連接,則返回-1;同理,recv會返回該客戶端發送過來的數據的字節數,如沒有數據到來,則返回-1。因此我們可以根據這兩個函數的返回值進行相應的操作。accept返回非負數的情況,說明有新的客戶請求連接,因此要把它記錄下來,以下次能收到它發送過來的信息。對於recv也一樣,如果返回值為正數,則說明有數所到來,對數據作相應的處理返回復。
  經此一役,使用單進程的通信方式仍然可以實現服務器程序。可以使用上文中介紹的方法(telnet)對它進行測試。在測試的過程中,我們依然可以發現:服務器采用了非阻塞的方式進行讀,當沒有數據準備好的時候,它不停地循環,這樣浪費了大量的CPU時間。因此,本文的方案仍不是一個最好的方案。
 如果客戶端的通信量很少,那麽服務器會不停地循環,這樣就會占用很多CPU時間,使得其它進程使用的時間很少。

延伸阅读

评论