歡迎關(guān)注博主 Mindtechnist 或加入【Linux C/C++/Python社區(qū)】一起學(xué)習(xí)和分享Linux、C、C++、Python、Matlab,機(jī)器人運(yùn)動控制、多機(jī)器人協(xié)作,智能優(yōu)化算法,濾波估計、多傳感器信息融合,機(jī)器學(xué)習(xí),人工智能等相關(guān)領(lǐng)域的知識和技術(shù)。
專欄:《網(wǎng)絡(luò)編程》
什么是并發(fā)服務(wù)器
當(dāng)涉及到構(gòu)建高性能的服務(wù)器應(yīng)用程序時,我們通常會考慮使用并發(fā)服務(wù)器來處理多個客戶端請求。在并發(fā)服務(wù)器中,多進(jìn)程和多線程是兩種常見的并發(fā)模型,它們都有各自的優(yōu)點(diǎn)和適用場景。本文將介紹多進(jìn)程和多線程并發(fā)服務(wù)器的基礎(chǔ)知識。
多進(jìn)程并發(fā)服務(wù)器
多進(jìn)程并發(fā)服務(wù)器通過創(chuàng)建多個子進(jìn)程來處理客戶端請求。每個子進(jìn)程是操作系統(tǒng)中獨(dú)立運(yùn)行的單位,擁有自己的內(nèi)存空間和資源。當(dāng)有新的客戶端連接請求到達(dá)時,服務(wù)器創(chuàng)建一個新的子進(jìn)程來處理該請求。子進(jìn)程負(fù)責(zé)與客戶端通信并提供所需的服務(wù)。
多進(jìn)程并發(fā)服務(wù)器的優(yōu)點(diǎn)是穩(wěn)定性高。由于每個子進(jìn)程都是相互獨(dú)立的,一個子進(jìn)程的崩潰或錯誤不會影響其他子進(jìn)程的執(zhí)行。這種獨(dú)立性使得多進(jìn)程并發(fā)服務(wù)器能夠有效地隔離錯誤,提高服務(wù)器的可靠性。
然而,多進(jìn)程并發(fā)服務(wù)器也有一些缺點(diǎn)。創(chuàng)建和管理多個進(jìn)程需要消耗更多的系統(tǒng)資源,包括內(nèi)存和CPU時間。進(jìn)程間的通信也需要特殊的機(jī)制,例如管道或共享內(nèi)存,以便在不同進(jìn)程之間傳遞數(shù)據(jù)。此外,由于每個進(jìn)程都有自己的內(nèi)存空間,進(jìn)程間的數(shù)據(jù)共享和同步可能會變得復(fù)雜。
多線程并發(fā)服務(wù)器
多線程并發(fā)服務(wù)器通過創(chuàng)建多個線程來處理客戶端請求。線程是在進(jìn)程內(nèi)部運(yùn)行的獨(dú)立執(zhí)行流,共享同一個進(jìn)程的內(nèi)存空間和資源。與多進(jìn)程不同,多線程服務(wù)器不需要創(chuàng)建新的進(jìn)程來處理請求,而是在同一個進(jìn)程中創(chuàng)建多個線程。
多線程并發(fā)服務(wù)器的優(yōu)點(diǎn)是資源消耗較少。與進(jìn)程相比,線程的創(chuàng)建和切換開銷更小,因?yàn)樗鼈児蚕磉M(jìn)程的資源。這使得多線程并發(fā)服務(wù)器更加輕量級,能夠更高效地利用系統(tǒng)資源。
然而,多線程并發(fā)服務(wù)器也存在一些問題。首先,線程共享進(jìn)程的內(nèi)存空間,因此在多線程環(huán)境中訪問共享數(shù)據(jù)需要特殊的同步機(jī)制,以避免競態(tài)條件和數(shù)據(jù)不一致。其次,由于線程共享相同的地址空間,一個線程的錯誤可能會影響整個進(jìn)程,導(dǎo)致服務(wù)器崩潰或不穩(wěn)定。
選擇適合的并發(fā)模型
在選擇多進(jìn)程還是多線程并發(fā)服務(wù)器時,需要根據(jù)具體的應(yīng)用需求和性能要求進(jìn)行權(quán)衡。以下是一些建議:
- 如果穩(wěn)定性和容錯性是首要考慮因素,多進(jìn)程并發(fā)服務(wù)器可能是更好的選擇。每個子進(jìn)程的獨(dú)立性可以有效地隔離錯誤,提高服務(wù)器的可靠性。
- 如果服務(wù)器需要處理大量的并發(fā)連接并需要更高的性能和資源利用率,多線程并發(fā)服務(wù)器可能更適合。線程的創(chuàng)建和切換開銷相對較小,可以更高效地處理并發(fā)請求。
- 如果同時需要穩(wěn)定性和性能,可以考慮使用混合模型,即在每個進(jìn)程中創(chuàng)建多個線程,以實(shí)現(xiàn)更好的負(fù)載平衡和資源利用率。
無論選擇多進(jìn)程還是多線程并發(fā)服務(wù)器,都需要注意正確處理并發(fā)訪問共享數(shù)據(jù)的問題,使用適當(dāng)?shù)耐綑C(jī)制(如鎖、信號量)來保證數(shù)據(jù)的一致性和正確性。
總結(jié)起來,多進(jìn)程和多線程并發(fā)服務(wù)器是實(shí)現(xiàn)高性能服務(wù)器的常見方式。它們各有優(yōu)劣,選擇合適的并發(fā)模型需要考慮應(yīng)用需求和性能要求,并注意處理并發(fā)訪問共享數(shù)據(jù)的問題。
多進(jìn)程并發(fā)服務(wù)器代碼實(shí)現(xiàn)
使用多進(jìn)程并發(fā)服務(wù)器時要考慮以下幾點(diǎn):
- 父進(jìn)程最大文件描述個數(shù)(父進(jìn)程中需要close關(guān)閉accept返回的新文件描述符);
- 系統(tǒng)內(nèi)創(chuàng)建進(jìn)程個數(shù)(與內(nèi)存大小相關(guān));
- 進(jìn)程創(chuàng)建過多是否降低整體服務(wù)性能(進(jìn)程調(diào)度);
server
/* server.c */
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include "wrap.h"
#define MAXLINE 80
#define SERV_PORT 800
void do_sigchild(int num)
{
while (waitpid(0, NULL, WNOHANG) > 0)
;
}
int main(void)
{
struct sockaddr_in servaddr, cliaddr;
socklen_t cliaddr_len;
int listenfd, connfd;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];
int i, n;
pid_t pid;
struct sigaction newact;
newact.sa_handler = do_sigchild;
sigemptyset(&newact.sa_mask);
newact.sa_flags = 0;
sigaction(SIGCHLD, &newact, NULL);
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
Listen(listenfd, 20);
printf("Accepting connections ...\n");
while (1) {
cliaddr_len = sizeof(cliaddr);
connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
pid = fork();
if (pid == 0) {
Close(listenfd);
while (1) {
n = Read(connfd, buf, MAXLINE);
if (n == 0) {
printf("the other side has been closed.\n");
break;
}
printf("received from %s at PORT %d\n",
inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
ntohs(cliaddr.sin_port));
for (i = 0; i < n; i++)
buf[i] = toupper(buf[i]);
Write(connfd, buf, n);
}
Close(connfd);
return 0;
} else if (pid > 0) {
Close(connfd);
} else
perr_exit("fork");
}
Close(listenfd);
return 0;
}
client
/* client.c */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include "wrap.h"
#define MAXLINE 80
#define SERV_PORT 6666
int main(int argc, char *argv[])
{
struct sockaddr_in servaddr;
char buf[MAXLINE];
int sockfd, n;
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
servaddr.sin_port = htons(SERV_PORT);
Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
while (fgets(buf, MAXLINE, stdin) != NULL) {
Write(sockfd, buf, strlen(buf));
n = Read(sockfd, buf, MAXLINE);
if (n == 0) {
printf("the other side has been closed.\n");
break;
} else
Write(STDOUT_FILENO, buf, n);
}
Close(sockfd);
return 0;
}
多線程并發(fā)服務(wù)器代碼實(shí)現(xiàn)
在使用線程模型開發(fā)服務(wù)器時需考慮以下問題:
- 調(diào)整進(jìn)程內(nèi)最大文件描述符上限;
- 線程如有共享數(shù)據(jù),考慮線程同步;
- 服務(wù)于客戶端線程退出時,退出處理(退出值,分離態(tài));
- 系統(tǒng)負(fù)載,隨著鏈接客戶端增加,導(dǎo)致其它線程不能及時得到CPU;
server
/* server.c */
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include "wrap.h"
#define MAXLINE 80
#define SERV_PORT 6666
struct s_info {
struct sockaddr_in cliaddr;
int connfd;
};
void *do_work(void *arg)
{
int n,i;
struct s_info *ts = (struct s_info*)arg;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];
/* 可以在創(chuàng)建線程前設(shè)置線程創(chuàng)建屬性,設(shè)為分離態(tài),哪種效率高內(nèi)? */
pthread_detach(pthread_self());
while (1) {
n = Read(ts->connfd, buf, MAXLINE);
if (n == 0) {
printf("the other side has been closed.\n");
break;
}
printf("received from %s at PORT %d\n",
inet_ntop(AF_INET, &(*ts).cliaddr.sin_addr, str, sizeof(str)),
ntohs((*ts).cliaddr.sin_port));
for (i = 0; i < n; i++)
buf[i] = toupper(buf[i]);
Write(ts->connfd, buf, n);
}
Close(ts->connfd);
}
int main(void)
{
struct sockaddr_in servaddr, cliaddr;
socklen_t cliaddr_len;
int listenfd, connfd;
int i = 0;
pthread_t tid;
struct s_info ts[256];
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
Listen(listenfd, 20);
printf("Accepting connections ...\n");
while (1) {
cliaddr_len = sizeof(cliaddr);
connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
ts[i].cliaddr = cliaddr;
ts[i].connfd = connfd;
/* 達(dá)到線程最大數(shù)時,pthread_create出錯處理, 增加服務(wù)器穩(wěn)定性 */
pthread_create(&tid, NULL, do_work, (void*)&ts[i]);
i++;
}
return 0;
}
client
/* client.c */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include "wrap.h"
#define MAXLINE 80
#define SERV_PORT 6666
int main(int argc, char *argv[])
{
struct sockaddr_in servaddr;
char buf[MAXLINE];
int sockfd, n;
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
servaddr.sin_port = htons(SERV_PORT);
Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
while (fgets(buf, MAXLINE, stdin) != NULL) {
Write(sockfd, buf, strlen(buf));
n = Read(sockfd, buf, MAXLINE);
if (n == 0)
printf("the other side has been closed.\n");
else
Write(STDOUT_FILENO, buf, n);
}
Close(sockfd);
return 0;
}
618圖書推薦
書籍是知識的海洋,計算機(jī)好書推薦
??????618,清華社 IT BOOK 多得圖書活動開始啦!活動時間為2023 年6 月7 日至6 月18 日,清華社為您精選多款高分好書,涵蓋了 C++、Java、Python、前端、后端、數(shù)據(jù)庫、算法與機(jī)器學(xué)習(xí)等多個IT 開發(fā)領(lǐng)域,適合不同層次的讀者。全場5 折,掃碼領(lǐng)券更有優(yōu)惠哦!快來京東點(diǎn)擊鏈接 IT BOOK多得查看詳情吧!文章來源:http://www.zghlxwxcb.cn/news/detail-480459.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-480459.html
到了這里,關(guān)于計算機(jī)網(wǎng)絡(luò)編程 | 并發(fā)服務(wù)器代碼實(shí)現(xiàn)(多進(jìn)程/多線程)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!