寫在前面
Linux網(wǎng)絡(luò)編程我是看視頻學(xué)的,Linux網(wǎng)絡(luò)編程,看完這個(gè)視頻大概網(wǎng)絡(luò)編程的基礎(chǔ)差不多就掌握了。這個(gè)系列是我看這個(gè)Linux網(wǎng)絡(luò)編程視頻寫的筆記總結(jié)。
高并發(fā)服務(wù)器
問題:
根據(jù)上一個(gè)筆記,我們可以寫出一個(gè)簡(jiǎn)單的服務(wù)端和客戶端通信,但是我們發(fā)現(xiàn)一個(gè)問題——服務(wù)器只能連接一個(gè)客戶端。然而在實(shí)際生活中,我們發(fā)現(xiàn)一個(gè)服務(wù)器連接的客戶端遠(yuǎn)遠(yuǎn)不止一個(gè),所以我們就要做一個(gè)高并發(fā)服務(wù)器。
解決方法:
回看之前的代碼,之所以只能一對(duì)一通信,是因?yàn)榉?wù)器只有一次執(zhí)行accept
的機(jī)會(huì),一旦建立連接成功,就會(huì)去進(jìn)行通信處理業(yè)務(wù),而其他想要建立連接的服務(wù)器就沒辦法建立連接。因此我們想到在Linux系統(tǒng)編程中學(xué)的進(jìn)程和線程,我們可以讓父進(jìn)程(主線程)去監(jiān)聽,一定有客戶端請(qǐng)求建立連接,我們就創(chuàng)建子進(jìn)程(其他線程)去和客戶端建立連接進(jìn)行通信,父進(jìn)程(主線程)繼續(xù)監(jiān)聽。
多進(jìn)程并發(fā)服務(wù)器
思路(步驟):
- 前期準(zhǔn)備工作:
- 先用
socket()
生成一個(gè)套接字lfd
用來監(jiān)聽 - 用
bind()
對(duì)第一步生成的套接字綁定地址結(jié)構(gòu)(綁的是服務(wù)器的地址結(jié)構(gòu)) - 用
listen()
函數(shù)設(shè)置lfd
的監(jiān)聽上限,最大是128.
- 先用
- 進(jìn)入循環(huán),
accept
與客戶端建立連接,得到用于通信的套接字的文件描述符cfd
-
fork()
創(chuàng)建子進(jìn)程 - 對(duì)于父進(jìn)程,由于父進(jìn)程只是監(jiān)聽,不需要與客戶端進(jìn)行通信,所以我們就關(guān)閉
cfd
,注冊(cè)信號(hào)捕捉函數(shù),用來回收子進(jìn)程,然后一直循環(huán)監(jiān)聽。 - 對(duì)于子進(jìn)程,由于子進(jìn)程只是進(jìn)行通信,不需要監(jiān)聽,所以我們就關(guān)閉
lfd
,然后就與客戶端進(jìn)行通信,處理業(yè)務(wù)。
源代碼:
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<signal.h>
#define PORT 6666
void sys_err(char* str)
{
perror(str);
exit(-1);
}
void wait_child(int signum) //信號(hào)捕捉,回收子進(jìn)程
{
while((waitpid(0,NULL,WNOHANG))>0);
// if(waitpid(0,NULL,0)!=-1)
// printf("disconnect a client successfully\n");
return;
}
int main()
{
struct sockaddr_in addr_s,addr_c;
socklen_t addr_c_len=sizeof addr_c;
int lfd,cfd,res,n;
pid_t pid;
struct sigaction act;
char buf[BUFSIZ],client_IP[1024];
lfd=socket(AF_INET,SOCK_STREAM,0);
if(lfd<0)
sys_err("socket error");
addr_s.sin_family=AF_INET;
addr_s.sin_port=htons(PORT);
addr_s.sin_addr.s_addr=htonl(INADDR_ANY);
res=bind(lfd,(struct sockaddr*)&addr_s,sizeof addr_s);
if(res==-1)
sys_err("bind error");
res=listen(lfd,128);
if(res==-1)
sys_err("listen error");
while(1)
{
cfd=accept(lfd,(struct socket*)&addr_c,&addr_c_len);
pid=fork(); //創(chuàng)建子進(jìn)程
if(pid==0) //子進(jìn)程
{
close(lfd); //打印客戶端的IP和端口號(hào),可以省略
printf("connect successfully,client IP:%s,port:%d\n",inet_ntop(AF_INET,&addr_c.sin_addr.s_addr,&client_IP,sizeof client_IP),ntohs(addr_c.sin_port));
break;
}
else if(pid>0)
{
close(cfd);
act.sa_handler=wait_child;
sigemptyset(&act.sa_mask);
act.sa_flags=0;
sigaction(SIGCHLD,&act,NULL);
continue;
}
}
if(pid==0) //父進(jìn)程
{
while(1)
{
n=read(cfd,buf,sizeof buf);
for(int i=0;i<n;i++)
buf[i]=toupper(buf[i]);
write(cfd,buf,n);
write(STDOUT_FILENO,buf,n);
}
}
close(cfd);
close(lfd);
return 0;
}
效果
多線程并發(fā)服務(wù)器
思路(步驟):
- 前期準(zhǔn)備工作:
- 先用
socket()
生成一個(gè)套接字lfd
用來監(jiān)聽 - 用
bind()
對(duì)第一步生成的套接字綁定地址結(jié)構(gòu)(綁的是服務(wù)器的地址結(jié)構(gòu)) - 用
listen()
函數(shù)設(shè)置lfd
的監(jiān)聽上限,最大是128.
- 先用
- 進(jìn)入循環(huán),
accept
與客戶端建立連接,得到用于通信的套接字的文件描述符cfd
- 創(chuàng)建子線程
- 對(duì)于子線程,由于子線程只是進(jìn)行通信,不需要監(jiān)聽,所以我們就關(guān)閉
lfd
,然后就與客戶端進(jìn)行通信,處理業(yè)務(wù)。 - 對(duì)于父進(jìn)程,由于父線程只是監(jiān)聽,不需要與客戶端進(jìn)行通信,所以我們就關(guān)閉
cfd
,然后設(shè)置線程pthread_detach()
分離或者使用pthread_join()
回收子線程。
源代碼
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include<unistd.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<pthread.h>
#define PORT 6666
void sys_err(char* str)
{
perror(str);
exit(-1);
}
void* fun(void* arg)
{
int cfd=(int) arg,n;
char buf[BUFSIZ];
while(1)
{
n=read(cfd,buf,sizeof buf);
if(n==0)
{
printf("one client closed......\n");
break;
}
for(int i=0;i<n;i++)
buf[i]=toupper(buf[i]);
write(cfd,buf,n);
write(STDOUT_FILENO,buf,n);
}
close(cfd);
return NULL;
}
int main()
{
struct sockaddr_in addr_s,addr_c;
socklen_t addr_c_len=sizeof addr_c;
char c_IP[1024];
int lfd,cfd,res;
pthread_t tid;
addr_s.sin_family=AF_INET;
addr_s.sin_port=htons(PORT);
addr_s.sin_addr.s_addr=htonl(INADDR_ANY);
lfd=socket(AF_INET,SOCK_STREAM,0);
if(lfd<0)
sys_err("socket errro");
res=bind(lfd,(struct sockaddr*)&addr_s,sizeof addr_s);
if(res<0)
sys_err("bind error");
res=listen(lfd,128);
if(res<0)
sys_err("listen error");
printf("accepting connect........\n");
while(1)
{
cfd=accept(lfd,(struct sockaddr*)& addr_c,&addr_c_len);
if(cfd==-1)
sys_err("accept error");
printf("connect successfully,client ip:%s,port:%d\n",inet_ntop(AF_INET,&addr_c.sin_addr.s_addr,c_IP,sizeof c_IP),ntohs(addr_c.sin_port));
res=pthread_create(&tid,NULL,fun,(void*)cfd);
if(res!=0)
fprintf(stderr,"pthread create error:%s",strerror(res));
pthread_detach(tid);
if(res!=0)
fprintf(stderr,"pthread create error:%s",strerror(res));
}
close(lfd);
return 0;
}
效果
寫在最后
個(gè)人親身經(jīng)驗(yàn):我們學(xué)習(xí)的一系列Linux命令,一定要自己親手去敲。不要只是看別人敲代碼,不要只是停留在眼睛看,腦袋以為自己懂了,等你實(shí)際上手去敲會(huì)發(fā)現(xiàn)許許多多的這樣那樣的問題。畢竟“實(shí)踐出真知”。
如果你覺得我寫的題解還不錯(cuò)的,請(qǐng)各位王子公主移步到我的其他題解看看
- 數(shù)據(jù)結(jié)構(gòu)與算法部分(還在更新中):
- C++ STL總結(jié) - 基于算法競(jìng)賽(強(qiáng)力推薦)
- 動(dòng)態(tài)規(guī)劃——01背包問題
- 動(dòng)態(tài)規(guī)劃——完全背包問題
- 動(dòng)態(tài)規(guī)劃——多重背包問題
- 動(dòng)態(tài)規(guī)劃——分組背包問題
- 動(dòng)態(tài)規(guī)劃——最長(zhǎng)上升子序列(LIS)
- 二叉樹的中序遍歷(三種方法)
- 最長(zhǎng)回文子串
- 最短路算法——Dijkstra(C++實(shí)現(xiàn))
- 最短路算法———Bellman_Ford算法(C++實(shí)現(xiàn))
- 最短路算法———SPFA算法(C++實(shí)現(xiàn))
- 最小生成樹算法———prim算法(C++實(shí)現(xiàn))
- 最小生成樹算法———Kruskal算法(C++實(shí)現(xiàn))
- 染色法判斷二分圖(C++實(shí)現(xiàn))
- Linux部分(還在更新中):
- Linux學(xué)習(xí)之初識(shí)Linux
- Linux學(xué)習(xí)之命令行基礎(chǔ)操作
- Linux學(xué)習(xí)之基礎(chǔ)命令(適合小白)
- Linux學(xué)習(xí)之權(quán)限管理和用戶管理
- Linux學(xué)習(xí)之制作靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)
- Linux學(xué)習(xí)之makefile
- Linux學(xué)習(xí)之系統(tǒng)編程1(關(guān)于讀寫系統(tǒng)函數(shù))
- Linux學(xué)習(xí)之系統(tǒng)編程2(關(guān)于進(jìn)程及其相關(guān)的函數(shù))
- Linux學(xué)習(xí)之系統(tǒng)編程3(進(jìn)程及wait函數(shù))
- Linux學(xué)習(xí)之系統(tǒng)編程4(進(jìn)程間通信)
- Linux學(xué)習(xí)之系統(tǒng)編程5(信號(hào))
- Linux學(xué)習(xí)之系統(tǒng)編程6(線程)
- Linux學(xué)習(xí)之系統(tǒng)編程7(線程同步/互斥鎖/信號(hào)量/條件變量)
- Linux學(xué)習(xí)之網(wǎng)絡(luò)編程(純理論)
- Linux學(xué)習(xí)之網(wǎng)絡(luò)編程2(socket,簡(jiǎn)單C/S模型)
???總結(jié)
“種一顆樹最好的是十年前,其次就是現(xiàn)在”
所以,
“讓我們一起努力吧,去奔赴更高更遠(yuǎn)的山海”
如果有錯(cuò)誤?,歡迎指正喲??文章來源:http://www.zghlxwxcb.cn/news/detail-789518.html
??如果覺得收獲滿滿,可以動(dòng)動(dòng)小手,點(diǎn)點(diǎn)贊??,支持一下喲??文章來源地址http://www.zghlxwxcb.cn/news/detail-789518.html
到了這里,關(guān)于Linux學(xué)習(xí)之網(wǎng)絡(luò)編程3(高并發(fā)服務(wù)器)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!