日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

开源 多进程 框架 c++_linux fork多进程并发服务器模型之C/C++代码实战

發布時間:2023/12/15 linux 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 开源 多进程 框架 c++_linux fork多进程并发服务器模型之C/C++代码实战 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

今天我們一起來聊聊多進程實現與多個客戶端進行通信。

如果是在while中循環accept, 然后循環處理事情, 此時, 這種服務是迭代服務, 只能逐一處理客戶端的請求, 后一個請求必須等前一個請求處理完畢, 無法并發處理, 真是急死人。 要實現并發, 我們可以考慮多線程, 也可以考慮多進程, 本文來說說后者。 在我們的多進程服務器模型中, 我們用父進程來處理連接(監聽socket), 用fork子進程的方法來處理通信(通信socket), 各司其職, 美哉。

一旦涉及到fork, 就必須注意僵尸進程的處理, 所以, 我們要用waitpid進行收尸, 這一點, 我們已經說過了。 另外, 要注意, 父子進程共享socket句柄的文件表(如果不理解的話, 建議看看APUE), 所以close socket的時候, 只是使引用計數減1, 并不是真正地直接關閉socket(減為0才是真正的關閉)。

廢話少說, 直接上菜。

服務端程序為:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

void sigChildFun(int sigNO)

{

pid_t pid;

int stat;

while((pid = waitpid(-1, &stat, WNOHANG)) > 0) // 循環收尸(僵尸進程), 此時waitpid不會阻塞

{

NULL;

}

return;

}

int main()

{

sockaddr_in servAddr;

memset(&servAddr,0,sizeof(servAddr));

servAddr.sin_family = AF_INET;

servAddr.sin_addr.s_addr = INADDR_ANY;

servAddr.sin_port = htons(8765);

int iListenSocket = socket(AF_INET, SOCK_STREAM, 0);

bind(iListenSocket, (sockaddr *)&servAddr, sizeof(servAddr));

listen(iListenSocket,5);

signal(SIGCHLD, sigChildFun);

while(1)

{

sockaddr_in clientAddr;

socklen_t iSize = sizeof(clientAddr);

memset(&clientAddr, 0, sizeof(clientAddr));

int iConnSocket = accept(iListenSocket,(sockaddr*)&clientAddr, &iSize);

if(iConnSocket < 0)

{

if(errno == EINTR || errno == ECONNABORTED)

{

continue;

}

else

{

printf("accept error, server");

return -1;

}

}

int tmpPid = fork();

if(tmpPid == 0)

{

close(iListenSocket); // 子進程讓監聽socket的計數減1, 并非直接關閉監聽socket

char szBuf[1024] = {0};

snprintf(szBuf, sizeof(szBuf), "server pid[%u], client ip[%s]", getpid(), inet_ntoa(clientAddr.sin_addr));

write(iConnSocket, szBuf, strlen(szBuf) + 1);

while(1)

{

if(read(iConnSocket, szBuf, 1) <= 0)

{

close(iConnSocket); // 子進程讓通信的socket計數減1

return -2; // 子進程退出

}

}

close(iConnSocket); // 子進程讓通信的socket計數減1

return 0; // 子進程退出

}

close(iConnSocket); // 父進程讓通信的socket計數減1

}

getchar();

close(iListenSocket); // 父進程讓監聽socket計數減1, 此時會關掉監聽socket(因為之前子進程已經有此操作)

return 0;

}

啟動它。

客戶端程序為:

我們開啟一個客戶端, 此時如下:

客戶端信息為:

服務端信息為:

可以看到, 服務端16402子進程是與客戶端通信的進程, 父進程16096是監聽的父進程(主進程)。

另外再開啟一個客戶端(不要關閉舊的客戶端), 此時如下:

新客戶端信息為:

服務端信息為:

可以看到, 父進程16096新開了一個子進程16497來與新的客戶端進行通信。

我們關閉第一個客戶端, 然后看到服務端為:

我們再關閉第二個客戶端, 然后看到服務端為:

顯然, 客戶端退出后, 發FIN包, 服務端子進程的recv函數就為0, 退出子進程的while循環了, 因此, 對應的子進程就over了, 而且不會留下僵尸進程(有waitpid)。 而且, 我們可以看到, 負責連接管理(accept)的父進程(主進程)依然安然無恙, 優哉游哉地等待下一個客戶端連接。

在這里, 我們可以看到, 這個服務器是并發的, 而不是迭代的。 什么意思呢? 你看, 即使子進程處理業務需要很久很久, 那么上述服務依然能并發地響應n個幾乎同時到達的客戶端, 此時,父進程開啟n個子進程, 并發地工作, 并發地與客戶端進行通信, 而且還互不干擾, 大大提升了服務滿意度。

注:需要C/C++ Linux服務器開發學習資料私信“資料”(資料包括C/C++,Linux,golang技術,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協程,DPDK,ffmpeg等),免費分享

總結

以上是生活随笔為你收集整理的开源 多进程 框架 c++_linux fork多进程并发服务器模型之C/C++代码实战的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。