Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2846205
  • 博文数量: 523
  • 博客积分: 11908
  • 博客等级: 上将
  • 技术积分: 5475
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-03 15:50
文章分类

全部博文(523)

文章存档

2019年(3)

2013年(4)

2012年(71)

2011年(78)

2010年(57)

2009年(310)

分类: LINUX

2009-07-12 01:56:11

并发服务器有三种设计模式:
多进程:每个进程服务一个客户端。优势是有各自独立的地址空间,可靠性高,但进程调度开销大,无法资源共享,进程间通信机制复杂。
多线程:每个线程服务一个客户端。优势是开销小,通信机制简单,可共享内存。但共享地址空间,可靠性低,一个服务器出现问题时可能导致系统崩溃,同时全局共享可能带来竞争,共享资源需要互斥,对编程要求高。
单进程:占有的进程及线程资源少,通信机制简单。但监听服务器及各个子服务器揉和在一起,程序结构复杂不清晰,编程麻烦。
 
 
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           /* These are the usual header files */
#include           /* for bzero() */
#include          /* for close() */
#include
#include
#include
#include
 
#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           /* These are the usual header files */
//#include           /* for bzero() only   can not be compiled for memcpy in c++*/
#include           /* for bzero() */
#include          /* for close() */
#include
#include
#include
#include
#include
#include    /* 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           /* These are the usual header files */
#include           /* for bzero() */
#include          /* for close() */
#include
#include
#include
#include
#include
#include
 
#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];
        }        
}
 
 
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/sailor_8318/archive/2008/12/30/3658912.aspx
阅读(1405) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~