与循环服务器的串行处理不同,并发服务器对服务请求并发处理。循环服务器只能够一个一个的处理客户端的请求,显然效率很低。并发服务器通过建立多个子进程来实现对请求的并发处理。并发服务器的一个难点是如何确定子进程的数据,因为不清楚请求客户端的数目,因此实现中通常采用事先分配一定数目的子进程与动态增加子进程相结合的方法来实现并发服务器。
简单并发服务器模型
/*
UDP简单并发服务器模型
*/
/*
服务器主进程
*/
socket(...);
bind(...);
fork();
//
创建多个子进程进行请求处理
while(1);
/* 服务器子进程1 */while(1)
{
recvfrom(....);
process(...);
sendto(.....);
}
close(...);
/* 服务器子进程2(同上) */
..................
..................
..................
/* 服务器子进程3(同上) */
..................
..................
..................
/*
TCP简单并发服务器模型
*/
/*
服务器主进程
*/
socket(...);
bind(...);
fork();
//
创建多个子进程进行请求处理
while(1);
/* 服务器子进程1 */
socket(...);
bind(...);
listen(...);
while(1)
{
accept(...);
recv(....)
process(...);
send(.....);
}
close(....);
/* 服务器子进程2(同上) */
..................
..................
..................
/* 服务器子进程3(同上) */
..................
..................
..................
一个并发服务器的例子
下面给出一个简单的并发服务器样子,仍然模拟服务器对外提供时间服务器,等待客户端到来,并返回给客户端服务器的当前时间。
UDP循环服务器
1
/*
* UDP并发服务器--server端程序*
*/
2 #include <sys/types.h>
3 #include <sys/socket.h>
4 #include <netinet/in.h>
5 #include <time.h>
6 #include <string.h>
7 #include <stdio.h>
8#define BUFFLEN 1024
9#define SERVER_PORT 12347
10#define BACKLOG 5
1112staticvoid handle_request(int s, struct sockaddr_in* from, char *buff)
13{
14 time_t now;
15int len = sizeof(*from);
16 memset(buff, 0, BUFFLEN);
17 now = time(NULL);
18 sprintf(buff, "%24srn",ctime(&now));
19 sendto(s, buff, strlen(buff),0, (struct sockaddr*)from, len);/*发送数据*/20}
2122staticvoid handle_connect(int s_s)
23{
24struct sockaddr_in from; /*客户端地址*/25int len = sizeof(from);
26int n = 0;
27char buff[BUFFLEN];
2829/*主处理过程*/30while(1)
31 {
32 memset(buff, 0, BUFFLEN);
33/*接收客户端连接*/34 n = recvfrom(s_s, buff, BUFFLEN,0,(struct sockaddr*)&from, &len);/*接收发送方数据*/35if(n > 0 && !strncmp(buff, "TIME", 4))/*判断是否合法接收数据*/36 {
37/*创建进程进行数据处理*/38if(!fork())
39 {
40 handle_request(s_s, &from, buff);/*处理连接请求*/41return ;
42 }
43 }
44 }
45}
464748int main(int argc, char *argv[])
49{
50int s_s; /*服务器套接字文件描述符*/51struct sockaddr_in local; /*本地地址*/5253/*建立TCP套接字*/54 s_s = socket(AF_INET, SOCK_STREAM, 0);
5556/*初始化地址接哦股*/57 memset(&local, 0, sizeof(local));
58 local.sin_family = AF_INET;/*AF_INET协议族*/59 local.sin_addr.s_addr = htonl(INADDR_ANY);/*任意本地地址*/60 local.sin_port = htons(SERVER_PORT);/*服务器端口*/6162/*将套接字文件描述符绑定到本地地址和端口*/63int err = bind(s_s, (struct sockaddr*)&local, sizeof(local));
6465/*处理客户端连接*/66 handle_connect(s_s);
6768 close(s_s);
6970return0;
71 }
TCP循环服务器
1
/*
* TCP并发服务器--server端程序*
*/
2 #include <sys/types.h>
3 #include <sys/socket.h>
4 #include <netinet/in.h>
5 #include <time.h>
6 #include <string.h>
7 #include <stdio.h>
8#define BUFFLEN 1024
9#define SERVER_PORT 12347
10#define BACKLOG 5
1112staticvoid handle_request(int s_c)
13{
14 time_t now;
15char buff[BUFFLEN];
16int n = 0;
17 memset(buff, 0, BUFFLEN);
18 n = recv(s_c, buff, BUFFLEN,0);/*接收发送方数据*/19if(n > 0 && !strncmp(buff, "TIME", 4))/*判断是否合法接收数据*/20 {
21 memset(buff, 0, BUFFLEN);
22 now = time(NULL);
23 sprintf(buff, "%24srn",ctime(&now));
24 send(s_c, buff, strlen(buff),0);/*发送数据*/25 }
26/*关闭客户端*/27 close(s_c);
28}
2930staticvoid handle_connect(int s_s)
31{
32int s_c; /*客户端套接字文件描述符*/33struct sockaddr_in from; /*客户端地址*/34int len = sizeof(from);
3536/*主处理过程*/37while(1)
38 {
39/*接收客户端连接*/40 s_c = accept(s_s, (struct sockaddr*)&from, &len);
41if(s_c > 0)/*客户端成功连接*/42 {
43/*创建进程进行数据处理*/44if(fork() > 0)/*父进程*/45 {
46 close(s_c);/*关闭父进程的客户端连接套接字*/47 }
48else49 {
50 handle_request(s_c);/*处理连接请求*/51return ;
52 }
53 }
54 }
55}
565758int main(int argc, char *argv[])
59{
60int s_s; /*服务器套接字文件描述符*/61struct sockaddr_in local; /*本地地址*/6263/*建立TCP套接字*/64 s_s = socket(AF_INET, SOCK_STREAM, 0);
6566/*初始化地址*/67 memset(&local, 0, sizeof(local));
68 local.sin_family = AF_INET;/*AF_INET协议族*/69 local.sin_addr.s_addr = htonl(INADDR_ANY);/*任意本地地址*/70 local.sin_port = htons(SERVER_PORT);/*服务器端口*/7172/*将套接字文件描述符绑定到本地地址和端口*/73int err = bind(s_s, (struct sockaddr*)&local, sizeof(local));
74 err = listen(s_s, BACKLOG);/*侦听*/7576/*处理客户端连接*/77 handle_connect(s_s);
7879 close(s_s);
8081return0;
82 }
注意,
1. 为了方便退出,server程序中对信号SIGINT信号进行了处理,此时所有的进程都会退出;
2. 并发服务器中的client程序与上一节介绍循环服务器时使用的client程序是一样的,这里不在贴出来,
请参考 Linux网络编程服务器模型选择之循环服务器 http://www.cnblogs.com/lizhenghn/p/3617608.html
原文:http://www.cnblogs.com/lizhenghn/p/3617666.html
【说明】:本文章由站长整理发布,文章内容不代表本站观点,如文中有侵权行为,请与本站客服联系(QQ:254677821)!