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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

Linux:多进程、多线程服务器的实现解析(有图有代码有真相!!!)

發(fā)布時(shí)間:2023/12/20 linux 56 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux:多进程、多线程服务器的实现解析(有图有代码有真相!!!) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、問(wèn)題引入

阻塞型的網(wǎng)絡(luò)編程接口


幾乎所有的程序員第一次接觸到的網(wǎng)絡(luò)編程都是從 listen()、send()、recv()等接口開(kāi)始的。使用這些接口可以很方便的構(gòu)建服務(wù)器 /客戶機(jī)的模型。
我們假設(shè)希望建立一個(gè)簡(jiǎn)單的服務(wù)器程序,實(shí)現(xiàn)向單個(gè)客戶機(jī)提供類似于“一問(wèn)一答”的內(nèi)容服務(wù)。


我們注意到,大部分的 socket接口都是阻塞型的。所謂阻塞型接口是指系統(tǒng)調(diào)用(一般是 IO接口)不返回調(diào)用結(jié)果并讓當(dāng)前線程一直阻塞,只有當(dāng)該系統(tǒng)

調(diào)用獲得結(jié)果或者超時(shí)出錯(cuò)時(shí)才返回。實(shí)際上,除非特別指定,幾乎所有的 IO接口 (包括 socket 接口 )都是阻塞型的。這給網(wǎng)絡(luò)編程帶來(lái)了一個(gè)很大的問(wèn)題,如在調(diào)用 send()的同時(shí),線程將被

阻塞,在此期間,線程將無(wú)法執(zhí)行任何運(yùn)算或響應(yīng)任何的網(wǎng)絡(luò)請(qǐng)求。這給多客戶機(jī)、多業(yè)務(wù)邏輯的網(wǎng)絡(luò)編程帶來(lái)了挑戰(zhàn)。這時(shí),很多程序員可能會(huì)選擇多線程的方式來(lái)解決這個(gè)問(wèn)題。


二、多進(jìn)程多線程

應(yīng)對(duì)多客戶機(jī)的網(wǎng)絡(luò)應(yīng)用,最簡(jiǎn)單的解決方式是在服務(wù)器端使用多線程(或多進(jìn)程)。多線程(或多進(jìn)程)的目的是讓每個(gè)連接都擁有獨(dú)立的線程(或進(jìn)

程),這樣任何一個(gè)連接的阻塞都不會(huì)影響其他的連接。具體使用多進(jìn)程還是多線程,并沒(méi)有?一個(gè)特定的模式。傳統(tǒng)意義上,進(jìn)程的開(kāi)

銷要遠(yuǎn)遠(yuǎn)大于線程,所以,如果需要同時(shí)為較多的客戶機(jī)提供服務(wù),則不推薦使用多進(jìn)程;如果單個(gè)服務(wù)執(zhí)行體需要消耗較多的 CPU 資源,譬如需要進(jìn)行

大規(guī)模或長(zhǎng)時(shí)間的數(shù)據(jù)運(yùn)算或文件訪問(wèn),則進(jìn)程較為安全。通常,使用pthread_create () 創(chuàng)建新線程,fork() 創(chuàng)建新進(jìn)程。



我們假設(shè)對(duì)上述的服務(wù)器 / 客戶機(jī)模型,提出更高的要求,即讓服務(wù)器同時(shí)為多個(gè)客戶機(jī)提供一問(wèn)一答的服務(wù)。于是有了如上的模型。
在上述的線程 / 時(shí)間圖例中,主線程持續(xù)等待客戶端的連接請(qǐng)求,如果有連接,則創(chuàng)建新線程,并在新線程中提供為前例同樣的問(wèn)答服務(wù)。
很多初學(xué)者可能不明白為何一個(gè) socket 可以 accept 多次。實(shí)際上,socket的設(shè)計(jì)者可能特意為多客戶機(jī)的情況留下了伏筆,讓 accept() 能夠返回一個(gè)新
的 socket。下面是 accept 接口的原型:輸入?yún)?shù) sockfd 是從 socket(),bind() 和 listen() 中沿用下來(lái)的 socket 句柄


值。執(zhí)行完 bind() 和 listen() 后,操作系統(tǒng)已經(jīng)開(kāi)始在指定的端口處監(jiān)聽(tīng)所有的連接請(qǐng)求,如果有請(qǐng)求,則將該連接請(qǐng)求加入請(qǐng)求隊(duì)列。調(diào)用 accept() 接口
正是從 socket s 的請(qǐng)求隊(duì)列抽取第一個(gè)連接信息,創(chuàng)建?一個(gè)與 socked同類的新的 socket 返回句柄。新的 socket 句柄即是后續(xù) read() 和 recv() 的輸入?yún)?br /> 數(shù)。如果請(qǐng)求隊(duì)列當(dāng)前沒(méi)有請(qǐng)求,則 accept() 將進(jìn)?入阻塞狀態(tài)直到有請(qǐng)求進(jìn)入隊(duì)列。


1、多進(jìn)程服務(wù)器、客戶端實(shí)現(xiàn)簡(jiǎn)單通信

fork_server.c:#include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/types.h> #include<sys/socket.h> #include<arpa/inet.h> #include<netinet/in.h> static int startup(const char *_ip,int _port) {int sock=socket(AF_INET,SOCK_STREAM,0);if(sock<0){perror("socket");return 3; }struct sockaddr_in local;local.sin_family=AF_INET;local.sin_port=htons(_port);local.sin_addr.s_addr=inet_addr(_ip);if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0){perror("bind");return 4;}if(listen(sock,10)<0){perror("listen");return 5;} } static void usage(const char *proc) {printf("usage:[local_ip] [local_port]",proc); } int main(int argc,char *argv[]) {if(argc!=3){usage(argv[0]);printf("usage");return 1;}int listen_sock=startup(argv[1],atoi(argv[2]));struct sockaddr_in peer;socklen_t len=sizeof(peer);while(1){int new_sock=accept(listen_sock,(struct sockaddr*)&peer,&len);if(new_sock>0){pid_t id=fork();if(id==0){//childclose(listen_sock);char buf[1024];while(1){ssize_t s=read(new_sock,buf,sizeof(buf)-1);if(s>0){buf[s]=0;printf("client say#%s\n",buf);write(new_sock,buf,strlen(buf));}else if(s==0){printf("client quick\n");}else{break;}}close(new_sock);exit(1);}else{//fatherclose(new_sock);if(fork()>0){exit(0);}}}else{perror("new_sock");return 2;}}return 0; }
fork_client.c:#include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/types.h> #include<sys/socket.h> #include<arpa/inet.h> #include<netinet/in.h> static void usage(const char *proc) {printf("usage:[server_ip] [server_port]",proc); } int main(int argc,char *argv[]) {int sock=socket(AF_INET,SOCK_STREAM,0);if(sock<0){perror("socket");return 1;}struct sockaddr_in server;server.sin_family=AF_INET;server.sin_port=htons(atoi(argv[2]));server.sin_addr.s_addr=inet_addr(argv[1]);if(connect(sock,(struct sockaddr*)&server,sizeof(server))<0){perror("connect");return 2;}char buf[1024];while(1){printf("please enter:");fflush(stdout);ssize_t s=read(0,buf,sizeof(buf)-1);if(s>0){buf[s-1]=0;write(sock,buf,strlen(buf));ssize_t _s=read(sock,buf,sizeof(buf)-1);if(_s>0){buf[_s]=0;printf("server echo:%s\n",buf);}}}close(sock);return 0; }

2、多線程實(shí)現(xiàn)簡(jiǎn)單服務(wù)器(遠(yuǎn)程登陸:telnet)

thread_server.c#include<stdio.h> #include<pthread.h> #include<stdlib.h> #include<sys/types.h> #include<sys/socket.h> #include<arpa/inet.h> #include<netinet/in.h> #include<string.h> void* handleRequest(void* arg) {char buf[10240];int sock=(int)arg;while(1){ssize_t s=read(sock,buf,sizeof(buf)-1);//successif(s>0){buf[s]=0;printf("%s\n",buf);const char *msg= "HTTP/1.1 200 OK\r\n\r\n<html><h1>This is title</h1></html>\r\n";write(sock,msg,strlen(msg));break;}else if(s==0) {printf("client is quit!\n");break;}else{perror("read");break;}}close(sock); } int startup(const char *_ip,int _port) {//create socketint sock=socket(AF_INET,SOCK_STREAM,0);if(sock<0){perror("socket");return 2;}int flag=1;setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));//bindstruct sockaddr_in local;local.sin_family=AF_INET;local.sin_port=htons(_port);local.sin_addr.s_addr=inet_addr(_ip);if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0){perror("bind");return 3;}//listenif(listen(sock,10)<0){perror("listen");return 4;}return sock; } static void usage(char *proc) {printf("usage:%s [server_ip] [server_port]",proc); } int main(int argc, char *argv[]) {if(argc!=3){usage(argv[0]);return 1;}int listen_sock=startup(argv[1],atoi(argv[2]));struct sockaddr_in peer;socklen_t len=sizeof(peer);while(1){int new_sock=accept(listen_sock,(struct sockaddr*)&peer,&len); if(new_sock<0){perror("accept");continue;}printf("client ip:%s,port:%d\n",inet_ntoa(peer.sin_addr),ntohs(peer.sin_port));pthread_t id;pthread_create(&id,NULL,handleRequest,(void*)new_sock);pthread_detach(id);}return 0; }






總結(jié)

以上是生活随笔為你收集整理的Linux:多进程、多线程服务器的实现解析(有图有代码有真相!!!)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。