`
yangyou230
  • 浏览: 1650208 次
文章分类
社区版块
存档分类

【Linux的高级应用编程】网络编程中并发服务器的设计模式

 
阅读更多

网络编程中并发服务器的设计模式

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];

}

}


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics