Linux网络编程之高级并发服务器.docx
- 文档编号:8121151
- 上传时间:2023-01-28
- 格式:DOCX
- 页数:11
- 大小:17.22KB
Linux网络编程之高级并发服务器.docx
《Linux网络编程之高级并发服务器.docx》由会员分享,可在线阅读,更多相关《Linux网络编程之高级并发服务器.docx(11页珍藏版)》请在冰豆网上搜索。
Linux网络编程之高级并发服务器
1.介绍
在上一节,我们介绍了Linux简单的并发服务器,通过在服务器端建立多个子进程,来接收客户端的请求,实现并发处理,但这种方式明显有缺陷,服务器并不知道客户端请求的数量,所以事先建立的进程数不好确定。
所以,这里介绍三种高级并发服务器模式。
第一种是服务器端统一accept,接收客户端的到来,然后为每个客户端分配一个进程去处理.第二种是统一accept接收请求,然后为每个客户端分配一个线程去处理。
第三种建立多个线程去处理客户端请求,每个线程独自监听客户端的请求。
显然,第一种方案解决了简单服务器的并发问题。
第二种方案其实是对第一种方案的改进,因为线程切换的开销明显要小于进程切换的开销。
第三种方案就是原来用进程去处理每个请求,现在换成用线程去处理,个人认为改进不是很大.
2.高级并发服务器算法流程
(1)统一accept,多进程
socket(...);
bind(...);
listen(...);
while
(1){
accept(...);
fork(...);//子进程
}
close(...);//关闭服务器套接字
子进程:
recv(...);
process(...);
send(...);
close(...);//关闭客户端
(2)统一accept,多线程
socket(...);
bind(...);
listen(...);
while
(1){
accept(...);
pthread_create(....);
}
close(...);//关闭服务器
线程1:
recv(....);
process(....);
send(...);
close(...);//关闭客户端
(3)accept放入每个线程
socket(...);
bind(...);
listen(...);
pthread_create(...);
pthread_join(...);//等待线程结束
close(...);//关闭服务器
线程1:
Mutex_lock//互斥锁
accept(...);
Mutex_unlock(...);
recv(...);
process(...);
send(...);
close(...);//客户端
3.相关例子
TCP服务器:
(1)统一accept多进程
服务器;
#include
#include
#include
#include
#include
#include
#include
/**
高级并发服务器
TCP统一accept
当有客户端到来时,为每个客户端建立进程,然后每个进程处理客户端的请求,动态的建立进程
**/
#definePORT8888
#defineBUFFERSIZE1024
#defineBACKLOG2
staticvoidhandle(intsc){//处理客户端的请求
charbuffer[BUFFERSIZE];
time_tnow;
intsize;
memset(buffer,0,BUFFERSIZE);
size=recv(sc,buffer,BUFFERSIZE,0);
if(size>0&&!
strncmp(buffer,"TIME",4)){//时间服务器,当客户端请求时间就把时间发送给客户端
memset(buffer,0,BUFFERSIZE);
now=time(NULL);
sprintf(buffer,"%24s\r\n",ctime(&now));
send(sc,buffer,strlen(buffer),0);
}
close(sc);
}
intmain(intargc,char*argv[]){
intret;
ints;
intsc;//用于服务器与客户端进行数据传输的套接字
structsockaddr_inserver_addr;
structsockaddr_inclient_addr;
intlen;
len=sizeof(client_addr);
//建立流式套接字
s=socket(AF_INET,SOCK_STREAM,0);
if(s<0){
perror("socketerror");
return-1;
}
//将地址结构绑定到套接字描述符上去
memset(&server_addr,0,sizeof(server_addr));
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(PORT);
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
ret=bind(s,(structsockaddr*)&server_addr,sizeof(server_addr));
if(ret==-1){
perror("binderror");
return-1;
}
ret=listen(s,BACKLOG);
if(ret<0){
perror("listenerror");
return-1;
}
while
(1){
sc=accept(s,(structsockaddr*)&client_addr,&len);
if(sc<0){
continue;
}
if(fork()==0){//子进程
handle(sc);
close(s);//子进程关闭用于监听的套接字
}else{
close(sc);//父进程关闭客户端套接字
}
}
}
客户端:
#include
#include
#include
#include
#include
#include
#include
#definePORT8888
#defineBUFFERSIZE1024
intmain(intargc,char*argv[]){
ints;
intret;
intsize;
structsockaddr_inserver_addr;
charbuffer[BUFFERSIZE];
s=socket(AF_INET,SOCK_STREAM,0);
if(s<0){
perror("socketerror");
return-1;
}
bzero(&server_addr,sizeof(server_addr));
//将地址结构绑定到套接字
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(PORT);
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
//连接服务器
ret=connect(s,(structsockaddr*)&server_addr,sizeof(server_addr));
if(ret==-1){
perror("connecterror");
return-1;
}
memset(buffer,0,BUFFERSIZE);
strcpy(buffer,"TIME");
size=send(s,buffer,strlen(buffer),0);
if(size<0){
perror("senderror");
return-1;
}
memset(buffer,0,BUFFERSIZE);
size=recv(s,buffer,BUFFERSIZE,0);
if(size<0){
perror("recverror");
return;
}
printf("%s",buffer);
close(s);
return0;
}
(2)统一accept多线程
服务器:
#include
#include
#include
#include
#include
#include
#include
/**
TCP并发服务器,采用多线程,每次客户端发送请求,主线程建立一个子线程,用于处理客户端的请求
线程具有速度快,占用资源少,数据可以共享等优点统一accept
**/
#definePORT8888
#defineBUFFERSIZE1024
#defineBACKLOG2
staticvoidhandle(void*sc1){
intsc;
time_tnow;
charbuffer[BUFFERSIZE];
intsize;
sc=*((int*)sc1);//转换成int指针,然后取值,sc1本身就是一个指针
memset(buffer,0,BUFFERSIZE);
size=recv(sc,buffer,BUFFERSIZE,0);
if(size>0&&!
strncmp(buffer,"TIME",4)){//请求服务器的时间
memset(buffer,0,BUFFERSIZE);//清0
now=time(NULL);
sprintf(buffer,"%24s\r\n",ctime(&now));
send(sc,buffer,strlen(buffer),0);//向客户端发送数据
}
close(sc);//关闭客户端
}
intmain(intargc,char*argv[]){
intret;
ints;
intsc;
intlen;
pthread_tthread1;//定义线程名
structsockaddr_inserver_addr,client_addr;
len=sizeof(client_addr);
//建立流式套接字
s=socket(AF_INET,SOCK_STREAM,0);
if(s<0){
perror("socketerror");
return-1;
}
//将服务器端的地址结构绑定到套接字描述符
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
server_addr.sin_port=htons(PORT);
ret=bind(s,(structsockaddr*)&server_addr,sizeof(structsockaddr_in));
if(ret<0){
perror("binderror");
return-1;
}
//监听
ret=listen(s,BACKLOG);
if(ret<0){
perror("listenerror");
return-1;
}
//接收客户端的请求
for(;;){
sc=accept(s,(structsockaddr*)&client_addr,&len);
if(sc<0){
continue;
}else{
pthread_create(&thread1,NULL,handle,(void*)&sc);//建立线程,让线程去处理,最后一个字段是传递给线程处理函数handle的参数
}
}
close(s);
}
客户端:
#include
#include
#include
#include
#include
#include
#include
#definePORT8888
#defineBUFFERSIZE1024
intmain(intargc,char*argv[]){
ints;
intret;
intsize;
structsockaddr_inserver_addr;
charbuffer[BUFFERSIZE];
s=socket(AF_INET,SOCK_STREAM,0);
if(s<0){
perror("socketerror");
return-1;
}
bzero(&server_addr,sizeof(server_addr));
//将地址结构绑定到套接字
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(PORT);
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
//连接服务器
ret=connect(s,(structsockaddr*)&server_addr,sizeof(server_addr));
if(ret==-1){
perror("connecterror");
return-1;
}
memset(buffer,0,BUFFERSIZE);
strcpy(buffer,"TIME");
size=send(s,buffer,strlen(buffer),0);
if(size<0){
perror("senderror");
return-1;
}
memset(buffer,0,BUFFERSIZE);
size=recv(s,buffer,BUFFERSIZE,0);
if(size<0){
perror("recverror");
return;
}
printf("%s",buffer);
close(s);
return0;
}
(3)单独线程accept
服务器:
#include
#include
#include
#include
#include
#include
#include
#include
/**
多线程TCP并发服务器
主线程创建多个线程,然后每个线程独立的accept和进行数据的发送与接收
多线程,独立accept
**/
#definePORT8888
#defineBUFFERSIZE1024
#defineBACKLOG2
#defineCLIENTNUM3
staticvoid*handle(void*s1){
ints;
intlen;
intsc;
pthread_mutex_talock=PTHREAD_MUTEX_INITIALIZER;
charbuffer[BUFFERSIZE];
intsize;
structsockaddr_inclient_addr;
s=*((int*)s1);//得到服务器端的套接字描述符
//等待客户端连接
len=sizeof(client_addr);
for(;;){//不停的循环等待客户端的连接
time_tnow;
//进入互斥区,每次一个线程处理客户端
pthread_mutex_lock(&alock);
sc=accept(s,(structsockaddr*)&client_addr,&len);
pthread_mutex_unlock(&alock);
memset(buffer,0,BUFFERSIZE);
size=recv(sc,buffer,BUFFERSIZE,0);
if(size>0&&!
strncmp(buffer,"TIME",4)){
memset(buffer,0,BUFFERSIZE);
now=time(NULL);
sprintf(buffer,"%24s\r\n",ctime(&now));
send(sc,buffer,strlen(buffer),0);
}
close(sc);//关闭客户端
}
}
intmain(intargc,char*argv[]){
intret;
ints;
intlen;
inti;
pthread_tthread[CLIENTNUM];
structsockaddr_inserver_addr;
//建立流式套接字
s=socket(AF_INET,SOCK_STREAM,0);
if(s<0){
perror("socketerror");
return-1;
}
//将地址结构绑定到套接字上
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
server_addr.sin_port=htons(PORT);
ret=bind(s,(structsockaddr*)&server_addr,sizeof(structsockaddr_in));
if(ret==-1){
perror("binderror");
return-1;
}
//监听
ret=listen(s,BACKLOG);
if(ret==-1){
perror("listenerror");
return-1;
}
//建立3个线程,每个线程独立的accept
for(i=0;i pthread_create(&thread[i],NULL,handle,(void*)&s);//线程的处理函数为handle,传递的参数为套接字描述符s } //while (1); //等待线程结束 for(i=0;i pthread_join(thread[i],NULL); } //关闭套接字 close(s); return0; } 客户端: #include #include #include #include #include #include #include #definePORT8888 #defineBUFFERSIZE1024 intmain(intargc,char*argv[]){ ints; intret; intsize; structsockaddr_inserver_addr; charbuffer[BUFFERSIZE]; s=socket(AF_INET,SOCK_STREAM,0); if(s<0){ perror("socketerror"); return-1; } bzero(&server_addr,sizeof(server_addr)); //将地址结构绑定到套接字 server_addr.sin_family=AF_INET; server_addr.sin_port=htons(PORT); server_addr.sin_addr.s_addr=htonl(INADDR_ANY); //连接服务器 ret=connect(s,(structsockaddr*)&server_addr,sizeof(server_addr)); if(ret==-1){ perror("connecterror"); return-1; } memset(buffer,0,BUFFERSIZE); strcpy(buffer,"TIME"); size=send(s,buffer,strlen(buffer),0); if(size<0){ perror("senderror"); return-1; } memset(buffer,0,BUFFERSIZE); size=recv(s,buffer,BUFFERSIZE,0); if(size<0){ perror("recverror"); return; } printf("%s",buffer); close(s); return0; } 总结: 统一accept,多进程服务器是对简单并发服务器的改进,而由于进程的切换开销比较大,所以又有了统一accept,多线程的并发服务器。 而单独线程的accept是完全用线程来处理请求。 这些都是TCP服务器,由于UDP是突发的数据流,没有三次握手,所以服务器不能检测到客户端什么时候发送数据。 以上三种高级并发服务器仍然存在着性能问题,下一节介绍的I/O复用的循环服务器是对这三种高级并发服务器的改进。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Linux 网络 编程 高级 并发 服务器