1. 程式人生 > >C/S模式下---多程序程式設計

C/S模式下---多程序程式設計

在單程序下進行socket的程式設計,伺服器通過accept()獲取到客戶端的檔案描述符,並且與該客戶端進行互動。但是實際有兩方面的因素都促使伺服器應該能夠同時與多個客戶端進行互動。

1.listen()函式將已經完成三次握手和即將完成三次握手的客戶端檔案描述符存放到佇列中。
2.在實際客戶端與伺服器進行互動時,伺服器必須能夠同時與多個客戶端進行互動。

多程序程式設計的優勢:
1.能夠處理同時處理多個客戶端的連線,並且能夠與客戶端進行互動。
2.子程序可以共享fork()之間父程序開啟的檔案描述符,而不需要在程序之間傳遞檔案描述符,簡化了程式設計。
3.伺服器處理的每個客戶連線都是相互獨立的,因為程序之間是相互獨立的。。
4.任務分派明確,父程序只需處理客戶端的連線,子程序只需要與客戶端程序互動即可。

多程序伺服器端程式碼:

#include <sys/scoket.h>
#include <arpa/inet>  
#include <netinet/in.h>
#include <assert.h>
#Include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>

void zmobie(){
	wait(NULL);
}

void communicateWithCli(int c){
	char buff[128] = {0};
	while(1){
		int n = recv(c,buff,127,0);
		if(n<=0){
			printf("one client quit!");
			break;
		}
		printf("%d : %s",c,buff);
		send(c,"OK",2,0);
	}
}

int main(){
	signal(SIGCHLD,zmobie);
	int fd = socket(AF_INET,SOCK_STREAM,0);
	assert(fd!=-1);
	
	struct sockaddr_in cli,ser;
	ser.sin_family = AF_INET;
	ser.sin_port = htons(5000);
	ser.sin_addr.s_addr = inet_addr("127.0.0.1");

	int res = bind(fd,(struct sockaddr*)&ser,sizeof(ser));
	assert(res!=-1);	

	res = listen(fd,5);
	assert(res!=-1);

	while(1){
		socklen_t len = sizeof(cli);
		int c = accept(fd,(struct sockaddr*)&cli,&len);
		if(c==-1){
			printf("link error!");
			continue;//繼續進行連線
		}
		pid_t pid = fork();
		assert(pid!=-1);
		//子程序
		if(pid==0){
			communicateWithCli(c);
			exit(0);//向父親發出訊號,避免成為僵死程序,因為父程序是一直啟動的
		}
		//父程序
		else{
			close(c);
		}
	}
	close(fd);
	return 0;
}

執行結果:
在這裡插入圖片描述
在這裡插入圖片描述
從執行結果可以看出,有四個客戶端可以同時和伺服器進行互動,通過多程序的方式就解決了在最前提出的問題。

值得探究的是為什麼每次伺服器端輸出的客戶端的檔案描述符都是4?

在這裡插入圖片描述
為什麼在父程序中需要關閉客戶端的檔案描述符?
檔案描述符作為程序的資源是有限的,處於C/S的模式下,主程序只需要負責與客戶端連線,而不需要去做具體的邏輯處理。連線之後就不需要該客戶端的檔案描述符了,具體與客戶端進行互動的程序中已經拿到對應的檔案描述符了。因此,在父程序中關閉客戶端的檔案描述符可以減少不必要的資源浪費。

基於C/S模式,採用多程序程式設計的缺點
1.在系統可以開啟的程序是有限個數的,為每一個客戶端分配一個程序開銷太大

,如果客戶端佔著不用,或者只有少量資料的傳輸,開程序是划不來的。
2.一個客戶端獨佔一個程序,資源浪費。
3.當客戶端退出時,子程序結束。
4.如果由大量的客戶端同時連線伺服器,伺服器可能會崩潰。