Unix 網絡編程(2)——TCP API

TCP C/S套接口函數通常調用過程及基本函數

image

如上圖所示的TCP鏈接的基本過程。通常來講,服務器先於客戶端運行,服務器程序運行的基本過程是:服務器

  1. socket()函數建立服務器段socket。
  2. bind()函數進行端口綁定,或者不調用bind()函數而在調用listen()或者connect()函數時,內核爲套接口分配一個臨時端口。
  3. listen()函數進行監聽。
  4. accept()函數在接受客戶端的鏈接請求後,建立一個所謂的已鏈接socket,這個已鏈接socket在雙方鏈接過程當中存在,當服務完成以後就被關閉。

以上是鏈接創建的過程當中服務器的流程,而客戶端有一些不一樣:併發

  1. 一樣的在客戶端建立socket。
  2. 調用connect函數嘗試鏈接服務器。如connect失敗,則該套接口不在可用必須關閉,從新調用socket()。

 

fork和併發服務器

#include <sys/types.h>
#include <unistd.h>
/*
功能:複製進程
參數:無
返回值:  成功:  父進程:返回子進程id
                子進程:返回0
         失敗:  返回-1
*/
pid_t fork(void);

由fork建立的新進程被稱爲子進程(child process)。該函數被調用一次,但返回兩次。兩次返回的區別是子進程的返回值是0,而父進程的返回值則是新進程(子進程)的進程 id。將子進程id返回給父進程的理由是:由於一個進程的子進程能夠多於一個,沒有一個函數使一個進程能夠得到其全部子進程的進程id。 對子進程來講,之因此fork返回0給它,是由於它隨時能夠調用getpid()來獲取本身的pid;也能夠調用getppid()來獲取父進程的id。(進程id 0老是由交換進程使用,因此一個子進程的進程id不可能爲0 )。socket

fork以後,操做系統會複製一個與父進程徹底相同的子進程,雖然說是父子關係,可是在操做系統看來,他們更像兄弟關係,這2個進程共享代碼空間,可是數據空間是互相獨立的,子進程數據空間中的內容是父進程的完整拷貝,指令指針也徹底相同,子進程擁有父進程當前運行到的位置(兩進程的程序計數器pc值相同,也就是說,子進程是從fork返回處開始執行的),但有一點不一樣,若是fork成功,子進程中fork的返回值是0,父進程中fork的返回值是子進程的進程號,若是fork不成功,父進程會返回錯誤。函數

 

服務器在服務多用戶時,可用fork子進程來服務每個客戶。併發服務器的典型過程是:spa

  1. 服務器建立監聽socket。
  2. 綁定端口bind()並監聽。
  3. 父進程調用accept()函數。
  4. fork子進程。此時fork的子進程能夠共享以前父進程擁有的全部資源,固然也包括accept返回的已鏈接socket。
  5. 子進程關閉監聽socket。注意:此處子進程關閉的監聽socket是從父進程共享而來,由於子進程要負責本身的任務,再也不接納其它。子進程建立以後監聽socket的引用計數爲2,那麼此時子進程關閉監聽socket只是讓該socket的引用計數減1,並不會真正關閉,由於父進程還須要使用這個監聽socket。
  6. 父進程關閉已鏈接socket。和監聽socket同樣,此時的已鏈接socket也只是計數器減1,至關於父進程把鏈接全權交給了子進程(以前至關因而一對二的關係)。
  7. 子進程完成任務。
  8. 子進程關閉已鏈接socket。子進程完成任務以後關閉已鏈接socket,這時便真正關閉socket了。
相關文章
相關標籤/搜索