網路程式設計小結(三) 利用多程序與多執行緒

2021-10-02 03:31:46 字數 3947 閱讀 1141

在第一節的例子中,伺服器是乙個時間獲取程式,只要一次write呼叫就能立刻完成客戶端的任務,但是我們要想的是,服務端不一定每次都會這麼快的完成任務,所以,要想辦法加快服務端的處理速度。

首先可以想到的是並行處理,c++有兩種方式,乙個是多程序,乙個是多執行緒。下面描述這兩種辦法。

一、壓力測試

我們的客戶端應當有能力判斷服務端處理的快慢,所以我們要寫乙個壓力測試函式:

void request_to_server(int id,const char* ip,const uint16_t port){

int sockfd=socket(af_inet,sock_stream,0);

const char *id_str=std::to_string(id).c_str();

sockaddr_in addr;

bzero(&addr,sizeof(addr));

addr.sin_family=af_inet;

addr.sin_port=htons(port);

inet_pton(af_inet,ip,&addr.sin_addr);

connect(sockfd,(const sockaddr*)&addr,sizeof(addr));

const int buffersize=1024;

char buf[buffersize];

write(sockfd,id_str,strlen(id_str));

cout<

for(int i=0;i壓力測試函式利用多執行緒,指定使用者數和每個使用者發起的請求數,可以計算出總的處理時間。

對於我們前面的時間伺服器程式——乙個迭代處理方式(也就是最慢的那種),我們用100個使用者發起10次請求/人。

輸出:answer message(89):sun jan 12 19:25:44 2020

answer message(96):sun jan 12 19:25:44 2020

answer message(41):sun jan 12 19:25:44 2020

all task finish. used time=430 ms

上面是返回資料的一部分,下面是計算得到的總時間是430ms。

二、慢伺服器

1、迭代做法

void slow_handle_function(int id=0){

cout<

void server1(){

const uint16_t listened_port=9000;

const char* localhost="127.0.0.1";

const int listening_queue_length=1024;

const int buffersize=1024;

int listen_fd=socket(af_inet,sock_stream,0);

sockaddr_in server_addr;

bzero(&server_addr,sizeof(server_addr));

server_addr.sin_family=af_inet;

in_addr temp;

inet_pton(af_inet,localhost,&server_addr.sin_addr);

//server_addr.sin_addr.s_addr=htonl(temp.s_addr);

server_addr.sin_port=htons(listened_port);

bind(listen_fd,(const sockaddr*)&server_addr,sizeof(server_addr));

listen(listen_fd,listening_queue_length);

char buffer[buffersize];

while(1){

sockaddr_in client_addr;

socklen_t len=sizeof(client_addr);

cout<

執行10個客戶,每個發起5次請求,結果是:

pressure_test(10,5);

answer message(4):4

answer message(8):8

all task finish. used time=150.025 s

足足花了150s,其實挺好理解,每個處理花3s,一共3*10*5=150s;

2、以多程序為基礎的伺服器

void server2(){

const uint16_t listened_port=9000;

const char* localhost="127.0.0.1";

const int listening_queue_length=1024;

const int buffersize=1024;

int listen_fd=socket(af_inet,sock_stream,0);

sockaddr_in server_addr;

bzero(&server_addr,sizeof(server_addr));

server_addr.sin_family=af_inet;

in_addr temp;

inet_pton(af_inet,localhost,&server_addr.sin_addr);

//server_addr.sin_addr.s_addr=htonl(temp.s_addr);

server_addr.sin_port=htons(listened_port);

bind(listen_fd,(const sockaddr*)&server_addr,sizeof(server_addr));

listen(listen_fd,listening_queue_length);

char buffer[buffersize];

pid_t pid;

while(1){

sockaddr_in client_addr;

socklen_t len=sizeof(client_addr);

cout<

因此這個if裡面的內容都是針對子程序的。

首先關閉listend_fd,是因為只需要主程序監聽這個描述符就可以了,不需要子程序,但是由於子程序完全複製父程序的資料,所以,此時子程序首先就要關閉它,處理完後呼叫exit直接退出,在迴圈內,把剛才的connect_fd關閉,這個是針對父程序的,因為這個描述符不需要父程序來處理。

同樣和上面一樣的壓力測試:

answer message(10):10

answer message(6):6

answer message(5):5

all task finish. used time=15.0138 s

結果只有15s,快了10倍!

三、使用執行緒

學過作業系統的人都知道,程序的建立/銷毀代價很大,可能會嚴重影響效能。所以在現代的伺服器中使用的都是「多執行緒」而不是「多程序」。

c++11標準可以使用thread類來構造乙個執行緒處理每乙個請求。

void task_handle(int fd){

const int buffersize=1024;

char buffer[buffersize];

auto n=read(fd,buffer,buffersize);

buffer[n]='\0';

cout<

任務封裝到乙個函式裡面,並且這次由子執行緒關閉描述符,測試結果如下:

answer message(10):10

answer message(9):9

answer message(8):8

all task finish. used time=15.0064 s

如果說15s之外的時間是計算機處理執行緒或者程序的時間,那麼,雖然不是很明顯,但的確可以看見多執行緒快於多程序!

程序間通訊(三) 利用命名管道

程序間通訊 三 利用命名管道 程序間通訊的四種方式 1 剪貼簿 2 匿名管道 3 命名管道 4 郵槽 命名管道是通過網路來完成程序間的通訊,它遮蔽了底層的網路協議細節。我們在不了解網路協議的情況下,也可以利用命名管道來實現程序間的通訊。將命名管道作為一種網路程式設計方案時,它實際上建立了乙個客戶機 ...

網路程式設計基礎 併發程式設計 多程序

python中的多執行緒無法利用多核優勢,如果想要充分地使用多核cpu的資源 os.cpu count 檢視 在python中大部分情況需要使用多程序。python提供了multiprocessing multiprocessing模組用來開啟子程序,並在子程序中執行我們定製的任務 比如函式 該模組...

網路程式設計中多程序通訊

include include include include include include include include include int main len sizeof cliaddr cliaddr.sin family af inet 通過ip位址和埠號可以確定乙個連線到一台主機的...