您的位置:首页 > 理论基础 > 计算机网络

【嵌入式Linux学习七步曲之第七篇 Linux的高级应用编程】网络编程中并发服务器的设计模式

2008-12-30 23:46 1461 查看
网络编程中并发服务器的设计模式
Sailor_forever sailing_9806@163.com 转载请注明
http://blog.csdn.net/sailor_8318/archive/2008/12/30/3658912.aspx

并发服务器有三种设计模式:
多进程:每个进程服务一个客户端。优势是有各自独立的地址空间,可靠性高,但进程调度开销大,无法资源共享,进程间通信机制复杂。
多线程:每个线程服务一个客户端。优势是开销小,通信机制简单,可共享内存。但共享地址空间,可靠性低,一个服务器出现问题时可能导致系统崩溃,同时全局共享可能带来竞争,共享资源需要互斥,对编程要求高。
单进程:占有的进程及线程资源少,通信机制简单。但监听服务器及各个子服务器揉和在一起,程序结构复杂不清晰,编程麻烦。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// File: mult-pr-tcp-server.c
/*
多进程并发服务器。该程序等候客户连接,一旦连接则显示客户的地址,
接着接收该客户的名字并显示。然后接收来自该客户的信息(字符串)。
每当收到一个字符串,则显示该字符串,并将字符串反转,再将反转的字
符发回客户。之后,继续等待接收该客户的信息直至该客户关闭连接。服
务器具有同时处理多客户的能力。
*/
#include <stdio.h> /* These are the usual header files */
#include <strings.h> /* for bzero() */
#include <unistd.h> /* for close() */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define PORT 1234 /* Port that will be opened */
#define BACKLOG 2 /* Number of allowed connections */
#define MAXDATASIZE 1000
void process_cli(int connectfd, struct sockaddr_in client);

main()
{
int listenfd, connectfd; /* socket descriptors */
pid_t pid;
struct sockaddr_in server; /* server's address information */
struct sockaddr_in client; /* client's address information */
int sin_size;

/* Create TCP socket */
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
/* handle exception */
perror("Creating socket failed.");
exit(1);
}

int opt = SO_REUSEADDR;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

bzero(&server,sizeof(server));
server.sin_family=AF_INET;
server.sin_port=htons(PORT);
server.sin_addr.s_addr = htonl (INADDR_ANY);
if (bind(listenfd, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1) {
/* handle exception */
perror("Bind error.");
exit(1);
}

if(listen(listenfd,BACKLOG) == -1){ /* calls listen() */
perror("listen() error/n");
exit(1);
}

sin_size=sizeof(struct sockaddr_in);

while(1)
{
/*accept connection.what causes the acceptance? */
if ((connectfd = accept(listenfd,(struct sockaddr *)&client,&sin_size))==-1) {
perror("accept() error/n");
exit(1);
}
/* Create child process to service client */
if ((pid=fork())>0) {
/* parent process */
close(connectfd);
continue;
}
else if (pid==0) {
/*child process*/
close(listenfd);
process_cli(connectfd, client);
exit(0);
}
else {
printf("fork error/n");
exit(0);
}
}
close(listenfd); /* close listenfd */
}

void process_cli(int connectfd, struct sockaddr_in client)
{
int num;
char recvbuf[MAXDATASIZE], sendbuf[MAXDATASIZE], cli_name[MAXDATASIZE];

printf("You got a connection from %s. ",inet_ntoa(client.sin_addr) ); /* prints client's IP */
/* Get client's name from client */
num = recv(connectfd, cli_name, MAXDATASIZE,0);
if (num == 0) {
close(connectfd);
printf("Client disconnected./n");
return;
}
cli_name[num - 1] = '/0';
printf("Client's name is %s./n",cli_name);

while (num = recv(connectfd, recvbuf, MAXDATASIZE,0))
{
int i = 0;
recvbuf[num] = '/0';
printf("Received client( %s ) message: %s",cli_name, recvbuf);
for (i = 0; i < num - 1; i++) {
sendbuf[i] = recvbuf[num - i -2];
}
sendbuf[num - 1] = '/0';

send(connectfd,sendbuf,strlen(sendbuf),0); /* send to the client welcome message */
}
close(connectfd); /* close connectfd */
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// File: mult-thread-tcp-server.c
/*
多线程并发服务器。该程序实现多线程并发服务器
*/

#include <stdio.h> /* These are the usual header files */

//#include <strings.h> /* for bzero() only <strings.h> can not be compiled for memcpy in c++*/
#include <string.h> /* for bzero() */
#include <unistd.h> /* for close() */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <stdlib.h> /* for exit in c++(.C/.cc) ; no need for c ??*/

#define PORT 1234 /* Port that will be opened */
#define BACKLOG 5 /* Number of allowed connections */
#define MAXDATASIZE 1000

//void process_cli(int connectfd, sockaddr_in client); // c only supports struct sockaddr_in, but c++ support sockaddr_in
void process_cli(int connectfd, struct sockaddr_in client);
/* function to be executed by the new thread */
void* start_routine(void* arg);
typedef struct _ARG {
int connfd;
struct sockaddr_in client;
}ARG;
// it's better to use typedef struct
main()
{
int listenfd, connectfd; /* socket descriptors */
pthread_t thread;
//struct ARG *arg; // when no typedef,there should be struct for c code; no need for c++
ARG *arg;
struct sockaddr_in server; /* server's address information */
struct sockaddr_in client; /* client's address information */
int sin_size;

/* Create TCP socket */
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
/* handle exception */
perror("Creating socket failed.");
exit(1);
}

int opt = SO_REUSEADDR;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

bzero(&server,sizeof(server));
server.sin_family=AF_INET;
server.sin_port=htons(PORT);
server.sin_addr.s_addr = htonl (INADDR_ANY);
if (bind(listenfd, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1) {
/* handle exception */
perror("Bind error.");
exit(1);
}

if(listen(listenfd,BACKLOG) == -1){ /* calls listen() */
perror("listen() error/n");
exit(1);
}

sin_size=sizeof(struct sockaddr_in);
while(1)
{
/* Accept connection */
// if ((connectfd = accept(listenfd,(struct sockaddr *)&client,&sin_size))==-1) {// no problem for c
if ((connectfd = accept(listenfd,(struct sockaddr *)&client,(socklen_t *)&sin_size))==-1) {
perror("accept() error/n");
exit(1);
}
/* Create thread*/

arg = new ARG;
arg->connfd = connectfd;
//memcpy((void *)&arg->client, &client, sizeof(client)); // both ok!
memcpy(&arg->client, &client, sizeof(client));

if (pthread_create(&thread, NULL, start_routine, (void*)arg)) {
/* handle exception */
perror("Pthread_create() error");
exit(1);
}
}
close(listenfd); /* close listenfd */
}

void process_cli(int connectfd, sockaddr_in client)
{
int num;
char recvbuf[MAXDATASIZE], sendbuf[MAXDATASIZE], cli_name[MAXDATASIZE];

printf("You got a connection from %s. ",inet_ntoa(client.sin_addr) );
/* Get client's name from client */
num = recv(connectfd, cli_name, MAXDATASIZE,0);
if (num == 0) {
close(connectfd);
printf("Client disconnected./n");
return;
}
cli_name[num - 1] = '/0';
printf("Client's name is %s./n",cli_name);

while (num = recv(connectfd, recvbuf, MAXDATASIZE,0)) {
recvbuf[num] = '/0';
printf("Received client( %s ) message: %s",cli_name, recvbuf);
for (int i = 0; i < num - 1; i++) {
sendbuf[i] = recvbuf[num - i -2];
}
sendbuf[num - 1] = '/0';
send(connectfd,sendbuf,strlen(sendbuf),0);
}
close(connectfd); /* close connectfd */
}

void* start_routine(void* arg)
{
ARG *info;
info = (ARG *)arg;

/* handle client's requirement */
process_cli(info->connfd, info->client);

////delete arg will cause warning!the type for deleting should be the same as new allocated
delete info;
pthread_exit(NULL);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// File:singlethread-mult-tcp-server.C
/*单线程并发服务器实例。该程序采用单线程并发服务器算法实现的。*/
#include <stdio.h> /* These are the usual header files */
#include <string.h> /* for bzero() */
#include <unistd.h> /* for close() */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <stdlib.h>

#define PORT 1234 /* Port that will be opened */
#define BACKLOG 5 /* Number of allowed connections simutaniously*/
#define MAXDATASIZE 1000
typedef struct _CLIENT{
int fd;
char* name;
struct sockaddr_in addr; /* client's address information */
char* data;
} CLIENT;
void process_cli(CLIENT *client, char* recvbuf, int len);
void savedata(char* recvbuf, int len, char* data);

main()
{
int i, maxi, maxfd,sockfd;
int nready;
ssize_t n;
fd_set rset, allset;
int listenfd, connectfd; /* socket descriptors */
struct sockaddr_in server; /* server's address information */
/* client's information */
CLIENT client[FD_SETSIZE];
char recvbuf[MAXDATASIZE];
int sin_size;

/* Create TCP socket */
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
/* handle exception */
perror("Creating socket failed.");
exit(1);
}

int opt = SO_REUSEADDR;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

bzero(&server,sizeof(server));
server.sin_family=AF_INET;
server.sin_port=htons(PORT);
server.sin_addr.s_addr = htonl (INADDR_ANY);
if (bind(listenfd, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1) {
/* handle exception */
perror("Bind error.");
exit(1);
}

if(listen(listenfd,BACKLOG) == -1){ /* calls listen() */
perror("listen() error/n");
exit(1);
}

sin_size=sizeof(struct sockaddr_in);
/*initialize for select */
maxfd = listenfd;
maxi = -1;
for (i = 0; i < FD_SETSIZE; i++) {
client[i].fd = -1;
}
FD_ZERO(&allset);
FD_SET(listenfd, &allset);

while(1)
{
struct sockaddr_in addr;
rset = allset;
nready = select(maxfd+1, &rset, NULL, NULL, NULL);
printf("select saw rset actions and the readfset num is %d. /n",nready );

if (FD_ISSET(listenfd, &rset))
{ /* new client connection */
/* Accept connection */
printf("accept a connection./n");
if ((connectfd = accept(listenfd,(struct sockaddr *)&addr,(socklen_t *)&sin_size))==-1) {
perror("accept() error/n");
continue;
}

/* Put new fd to client */
for (i = 0; i < FD_SETSIZE; i++)
if (client[i].fd < 0) {
client[i].fd = connectfd; /* save descriptor */
client[i].name = new char[MAXDATASIZE];
client[i].addr = addr;
client[i].data = new char[MAXDATASIZE];
client[i].name[0] = '/0';
client[i].data[0] = '/0';
printf("You got a connection from %s. ",inet_ntoa(client[i].addr.sin_addr) );
break;
}

printf("add new connect fd./n");
if (i == FD_SETSIZE) printf("too many clients/n");
FD_SET(connectfd, &allset); /* add new descriptor to set */
if (connectfd > maxfd) maxfd = connectfd;
if (i > maxi) maxi = i;
if (--nready <= 0) continue; /* no more readable descriptors */
}

for (i = 0; i <= maxi; i++)
{
/* check all clients for data */
if ( (sockfd = client[i].fd) < 0) continue; /* no more connected clients*/

if (FD_ISSET(sockfd, &rset)) {
printf("recv occured for connect fd[%d]./n",i);
if ( (n = recv(sockfd, recvbuf, MAXDATASIZE,0)) == 0) {
/*connection closed by client */
close(sockfd);
printf("Client( %s ) closed connection. User's data: %s/n",client[i].name,client[i].data);
FD_CLR(sockfd, &allset);
client[i].fd = -1;
delete client[i].name;
delete client[i].data;
} else
process_cli(&client[i], recvbuf, n);
if (--nready <= 0) break; /* no more readable descriptors */
}
}
}
close(listenfd); /* close listenfd */
}

void process_cli(CLIENT *client, char* recvbuf, int len)
{
char sendbuf[MAXDATASIZE];

recvbuf[len-1] = '/0';
if (strlen(client->name) == 0) {
/* Got client's name from client */
memcpy(client->name,recvbuf, len);
printf("Client's name is %s./n",client->name);
return;
}

/* save client's data */
printf("Received client( %s ) message: %s/n",client->name, recvbuf);
/* save user's data */
savedata(recvbuf,len, client->data);
/* reverse usr's data */
for (int i1 = 0; i1 < len - 1; i1++) {
sendbuf[i1] = recvbuf[len - i1 -2];
}
sendbuf[len - 1] = '/0';

send(client->fd,sendbuf,strlen(sendbuf),0);
}

void savedata(char* recvbuf, int len, char* data)
{
int start = strlen(data);
for (int i = 0; i < len; i++) {
data[start + i] = recvbuf[i];
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐