Linux网络编程之高级并发服务器.docx

上传人:b****6 文档编号:8121151 上传时间:2023-01-28 格式:DOCX 页数:11 大小:17.22KB
下载 相关 举报
Linux网络编程之高级并发服务器.docx_第1页
第1页 / 共11页
Linux网络编程之高级并发服务器.docx_第2页
第2页 / 共11页
Linux网络编程之高级并发服务器.docx_第3页
第3页 / 共11页
Linux网络编程之高级并发服务器.docx_第4页
第4页 / 共11页
Linux网络编程之高级并发服务器.docx_第5页
第5页 / 共11页
点击查看更多>>
下载资源
资源描述

Linux网络编程之高级并发服务器.docx

《Linux网络编程之高级并发服务器.docx》由会员分享,可在线阅读,更多相关《Linux网络编程之高级并发服务器.docx(11页珍藏版)》请在冰豆网上搜索。

Linux网络编程之高级并发服务器.docx

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复用的循环服务器是对这三种高级并发服务器的改进。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 工学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1