這是程式的流程圖,每個人寫法不一樣流程圖也會稍微不同,不過大致上描述如圖
多人聊天室的架構為一個server端負責讓多個client來連線,所以server的工作就是負責大家的連線總管和群播訊息給所有用戶
首先是select的使用,詳細查詢manpage( http://linux.die.net/man/2/select ),這邊做簡單的說明,selectc函數是用來讓程式監視多個檔案控制代碼的狀態變化的,也就是程式(server端)在執行的時候調用select能夠處理一些事件的觸發(client連線),當沒有事件的時候程式處於等待未發生的事件狀態,程式會停在select這裡等待,直到被監視的檔案控制代碼有一個或多個發生了狀態改變。
select回傳值有3種: 小於0代表select發生錯誤;等於0代表逾時事件被觸發(timeout結構有設定才會執行);大於0代表成功執行並維持監聽狀態,監視有無內或外部事件觸發(與select的第二、三、四參數有關)
而select監控檔案的控制碼來判斷事件的觸發,檔案代碼也就是指一般的整數代碼 0 = 標準輸入;1=標準輸出;2=標準錯誤輸出。
int select(int sockfd, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
先從第二、三、四參數設定開始說明,所謂的fd_set型態變數就是指readfds、writefds、exceptfds,使用select之前必須先設定fd_set型態參數,然後把這些變數的位址&readfds、&writefds、&exceptfds傳遞給select函數來監控。這三個參數都是一個整數控制碼的集合(大於2的整數),其中readfds為第二個參數是用來指檔案系統狀態準備ok,可做讀取的動作;writefds為第三個參數是用來指檔案系統狀態準備ok,可做寫出;第四個參數是exceptfds代表額外特殊狀況發生處理的控制碼設定,通常不使用的話以NULL取代。第五個參數是計時器設定,設定的秒數內為select監聽的持續時間,一旦超出設定的時間select的回傳值為0。
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
而回來講第一個參數整數值的選擇必須是目前檔案整數代碼最大值+1,前面有提到基本系統具備的標準輸入(0)、標準輸出(1)、標準錯誤輸出(2)整數代碼,對Server端來說也具備基本的(0、1、2)之外,開啟與client連線後自己的sock值為3,第一個連線的Client端的clientfd(就是accpet()的回傳值)就是4,第二個連上的Client端的clientfd值為5,依此最大值的+1來做為select的第一個參數。
第二點是select函數內的參數使用,建立完連線之後(accept()...)開始以while迴圈來重覆做select的監控功能,所以第一件事必須先定義出fd_set型態參數,第二件事將這個檔案描述清單集合初始化歸零,再來第三件事就是加入這個清單內要讓select監聽的檔案整數代碼,第四件事設定計時器,處理select timeout(select回傳值為0)之後要處理的事情,第五件事select執行監控這些清單內的整數代碼有無事件發生,第六件事就是使用FD_ISSET()函數來判定監控清單內的整數代碼有發生變化就執行什麼事,前面的參數是檔案整數代碼;後面的參數是清單,例如監控清單內有加入clientfd的整數代碼,就可以偵測當server端收到訊息後進入此FD_ISSET(clientfd,&rfd) 函數內來做recv的接收訊息。
clientfd=accept(socket,...)
while(1) ///進入無窮迴圈
{
int stat;
fd_set rfd; //1.檔案描述字元型態,類似建立一個開關清單讓select來偵測
FD_ZERO(&rfd); //2. 初始化
FD_SET(clientfd,&rfd); //3. 增加要監聽的檔案狀態碼到清單中(例:0=基本輸入)
struct timeval timer; //4.設定計時器
timer.tv_sec =1; //秒單位
stat=select(clientfd+1,&rfd,NULL,NULL,&timer); //5.監聽清單內的狀態碼變化
.
if(stat<0){
perror("select error!");
}
else if(stat==0){
printf("timeout\n");
continue;
}
. else{
FD_ISSET(clientfd,&rfd) //6.若開關清單內的檔案狀態碼有變化(事件產生)就執行
{
recv
.......
} .
}}
第三點是多人聊天室的架構方式概念,有了整數代碼的概念再來就是如何發訊息,Server端主要負責的工作是將client端連上server,以及群播client的訊息給所有client知道,而群播的時候要計算和儲存client目前人數以及上線人數的最大值,如此一來才能準確的發送給有上線的client,下線的client就不被發送訊息否則會產生錯誤。注意的是如果client端離線而下一個client連線的整數代碼會是以client端整數代碼的最小值(4)開始往後填,因此要思考相同整數代碼但前後不同client上線的使用,需以產生一個二維陣列來存放整數代碼和對應的client名稱。
沒有留言:
張貼留言