首先是乙個tcp客戶/伺服器程式設計的例子
客戶端#include
"unp.h
"void
cli_echo(file
*fp,
intfd);
intmain(
intargc,
char
**ar**)
sockfd
=socket(af_inet, sock_stream, 0);
bzero(
&servaddr,
sizeof
(servaddr));
servaddr.sin_family
=af_inet;
servaddr.sin_port
=htons(serv_port);
inet_pton(af_inet, ar**[
1],
&servaddr.sin_addr);
connect(sockfd, (sa*)
&servaddr,
sizeof
(servaddr));
cli_echo(stdin, sockfd);
exit(0);
}void
cli_echo(file
*fp,
intfd)}
伺服器端
#include
"unp.h
"void
serv_echo(
intclifd);
void
sig_child(
intsigno);
intmain(
intargc,
char
**ar**)
if( (childpid
=fork()) ==0
)close(clifd);
}exit(0);
}void
serv_echo(
intclifd)
}void
sig_child(
intsigno)
正常啟動
首先伺服器程式啟動後,呼叫socket bind listen 和accept,並阻塞在accept。可以用netstat來檢測到伺服器程序有乙個處於listen狀態的套介面。然後啟動客戶程式,客戶呼叫socket connect後,引起tcp的三路握手過程。三路握手完成後,客戶程式從connect返回,伺服器程式從accept返回,到此tcp連線建立。伺服器程序產生乙個子程序用來處理於客戶的連線,伺服器主程序則繼續阻塞於accept呼叫,等待下乙個客戶連線。
連線建立後,客戶程式阻塞於fgets呼叫,等待使用者輸到此tcp連線建立。入一行。伺服器程式則阻塞於readline呼叫,等待客戶程式送出一行。此時可以通過netstat來檢測到:伺服器主程序處於listen狀態,伺服器子程序和客戶程序則處於established狀態。
正常終止
當對客戶程式鍵入eol字元(ctrl+c鍵)以終止客戶,立即執行netstat。可以檢測到客戶程式的套介面處於time_wait狀態,伺服器程式乙個套介面則處於listen狀態。
正常終止過程如下:客戶程式接受到終止字元後,從fgets返回乙個空指標,客戶程序呼叫exit後結束。於是,客戶套介面被核心關閉,並向伺服器傳送乙個fin,伺服器則以ack相應,此時客戶套介面處於fin_wait_2狀態,伺服器套介面處於close_wait狀態。
伺服器收到fin時,從readline呼叫返回並返回0,這導致伺服器子程序結束。伺服器的連線套介面隨之被關閉,伺服器子程序向客戶傳送乙個fin,客戶則以ack回應之,連線終止。客戶程序雖然結束,但是客戶程序套介面仍然處於time_wait狀態。
posix訊號
訊號是發生某事件時對程序的通知,也稱為為軟中斷。可以由乙個程序發往另乙個程序,也可以由核心發往程序。sigchld訊號就是程序終止時,核心傳送給終止程序父程序的訊號。每個訊號都有乙個處理方法,我們可以通過呼叫sigaction來設定我們自己的訊號處理程式,也可以通過設定sig_ign來忽略訊號,設定sig_dfl來設定預設的處理方法。
殭屍程序
設定程序為殭屍狀態的目的是為了維護子程序的資訊(子程序id、終止狀態和子程序的資源利用資訊)。如果乙個程序終止,且該程序仍有子程序處於殭屍狀態,則所有殭屍程序的父程序設為init程序。殭屍程序占用核心空間,所以我們應該避免程序變為殭屍程序,方法是wait waitpid系統呼叫。可以設定訊號sigchld的訊號處理程式,在此訊號處理程式裡呼叫wait或waitpid。這樣可以避免殭屍程序。
在某些系統上這樣作可能會導致伺服器程序錯誤。原因是伺服器子程序終止後,向父程序傳送乙個sigchld訊號,導致accept呼叫被中斷,某些系統在訊號處理程式執行完後不會重啟accept呼叫,而是返回eintr錯誤。由於我們的服務程式沒有處理這種錯誤,所以會導致錯誤。為了移植性,當我們編寫訊號處理程式時,必須對慢系統呼叫(可能常時間阻塞的系統呼叫)返回eintr有所裝備。收到eintr錯誤時,自己來重啟被中斷的系統呼叫。
用waitpid來防止產生殭屍程序
waitpid的wnohang選項,通知核心在沒有子程序終止時不要阻塞。
假如伺服器程式有5個子程序,每個程序負責處理乙個連線。則可能5個子程序同時終止,同時向父程序傳送sigchld訊號。而訊號處理程式只能對乙個訊號進行處理,只有乙個子程序正常終止,其餘4個子程序則成為殭屍程序。可以通過ps -s命令來進行驗證的確有4個子程序成為了殭屍程序。解決方法就是,迴圈呼叫witpid(加上wnohang選項)。
網路程式設計時注意的三種情況:
1 當派生子程序時,必須捕捉sigchld訊號,防止子程序結束時成為殭屍程序。
2 當捕捉訊號時,必須處理被中斷的系統斷用,因為有些系統不能重啟被中斷的系統呼叫,需要我們自己來重啟。
3 sigchld訊號的處理程式必須正確便學,應使用waitpid來避免多個子程序同時終止時,留下殭屍程序。
UNP讀書筆記三 TCP客戶 伺服器程式分析
首先是乙個tcp客戶 伺服器程式設計的例子 客戶端 include unp.h void cli echo file fp,intfd intmain intargc,char ar sockfd socket af inet,sock stream,0 bzero servaddr,sizeof ...
UNP讀書筆記二 常用TCP程式設計API
只是簡單介紹下每個函式的作用,很容易通過引數名知道每個引數的意義。int socket int family,int type,int protocol 此函式根據引數建立乙個指定的套介面,返回套介面描述符。int connect int sockfd,const struct sockaddr s...
UNP讀書筆記第三章
網路位元組序和主機位元組序大小端不一樣。linux提供了4個轉換函式 include uint16 t htons uint16 t value uint32 t htonl uint 32t value uint16 t ntohs uin16 t value uint32 t ntohl uin...