【嵌入式Linux学习七步曲之第七篇 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];

        }        

}

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值