Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2381443
  • 博文数量: 298
  • 博客积分: 7876
  • 博客等级: 准将
  • 技术积分: 5500
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-23 13:39
文章存档

2013年(2)

2012年(142)

2011年(154)

分类: LINUX

2011-04-04 15:53:41

6IO多路复用服务器

 

注:所以文章红色字体代表需要特别注意和有问题还未解决的地方,蓝色字体表示需要注意的地方

 

1.     本文所介绍的程序平台

开发板:arm9-mini2440

虚拟机为:Red Hat Enterprise Linux 5

开发板上系统内核版本:linux-2.6.32.2

 

 

2. IO多路复用

与多线程和多进程相比,I/O多路复用的最大优势是系统开销小,系统不需要建立新的进程或者线程,也不必维护这些线程和进程。

主要应用:

1)客户程序需要同时处理交互式的输入和服务器之间的网络连接

2)客户端需要对多个网络连接作出反应

3TCP服务器需要同时处理多个处于监听状态和多个连接状态的套接字

4)服务器需要处理多个网络协议的套接字

5)服务器需要同时处理不同的网络服务和协议

 

3. IO多路复用模式

4. select()函数

#include

int select(int nfds, fd_set *readfds, fd_set *wtitefds, fd_set *errnofds,

struct timeval *timeout)

注意:描述符不受限与套接字,任何描述符都行

nfdsselect()函数监视的描述符数的最大值,一般取监视的描述符数的最大值+1

其上限设置在sys/types.h中有定义

#define FD_SETSIZE 256

readfdsselect()函数监视的可读描述符集合

wtitefdsselect()函数监视的可写描述符集合

errnofdsselect()函数监视的异常描述符集合

timeoutselect()函数监视超时结束时间,取NULL表示永久等待

返回值:返回总的位数这些位对应已准备好的描述符,否则返回-1

相关宏操作:

       FD_ZERO(fd_set *fdset):清空fdset与所有描述符的关系

       FD_SET(int fd, d_set * fdset):建立描述符fdfdset得关系

       FD_CLR(int fd, d_set * fdset):撤销描述符fdfdset得关系

       FD_ISSET(int fd, d_set * fdset):检查与fdset联系的描述符fd是否可以读写,返回非零表示可以读写

5. select()函数实现IO多路复用的步骤

1)清空描述符集合

2)建立需要监视的描述符与描述符集合的关系

3)调用select函数

4)检查监视的描述符判断是否已经准备好

5)对已经准备好的描述符进程IO操作

 

6.单线程并发服务器设计实例

功能:

服务器等候客户连接请求,一旦连接成功显示客户地址,接收该客户的名字并显示,然后接收来自用户的信息,每收到一个字符串则显示,并将字符串反转,再将反转的字符串发回客户端。

 

客户端首先与服务器相连,接着发送客户端名字,然后发送客户信息,接收到服务器信息并显示,之后等待用户输入Crtl+D,就关闭连接并退出。

 

 

//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 */

    #define MAXDATASIZE 1000

    typedef struct CLIENT{

       int  fd;

       char*  name;

       struct sockaddr_in addr; /* client's address information */

       char* data;                     

    }; 

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

    socklen_t 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);

 

    if (FD_ISSET(listenfd, &rset)) {    /* new client connection */

       /* Accept connection */

       if ((connectfd = accept(listenfd,(struct sockaddr *)&addr,&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;

             }

          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;

          if (FD_ISSET(sockfd, &rset)) {

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

    }        

    }

 

 

 

 

// client.c

    #include

    #include

    #include

    #include

    #include

    #include

    #include         /* netbd.h is needed for struct hostent =) */

    #include

 

    #define PORT 1234   /* Open Port on Remote Host */

    #define MAXDATASIZE 100   /* Max number of bytes of data */

    void process(FILE *fp, int sockfd);

    char* getMessage(char* sendline,int len, FILE* fp);

 

    int main(int argc, char *argv[])

    {

    int fd;   /* files descriptors */

    struct hostent *he;         /* structure that will get information about remote host */

    struct sockaddr_in server;  /* server's address information */

 

    if (argc !=2) {      

       printf("Usage: %s \n",argv[0]);

       exit(1);

       }

 

    if ((he=gethostbyname(argv[1]))==NULL){ /* calls gethostbyname() */

       printf("gethostbyname() error\n");

       exit(1);

       }

 

    if ((fd=socket(AF_INET, SOCK_STREAM, 0))==-1){  /* calls socket() */

       printf("socket() error\n");

       exit(1);

       }

 

    bzero(&server,sizeof(server));

    server.sin_family = AF_INET;

    server.sin_port = htons(PORT); /* htons() is needed again */

    server.sin_addr = *((struct in_addr *)he->h_addr); 

 

    if(connect(fd, (struct sockaddr *)&server,sizeof(struct sockaddr))==-1){ /* calls connect() */

       printf("connect() error\n");

       exit(1);

       }

 

    process(stdin,fd);

 

    close(fd);   /* close fd */ 

    }

 

    void process(FILE *fp, int sockfd)

    {

    char    sendline[MAXDATASIZE], recvline[MAXDATASIZE];

    int numbytes;

 

    printf("Connected to server. \n");

    /* send name to server */

    printf("Input name : ");

    if ( fgets(sendline, MAXDATASIZE, fp) == NULL) {

       printf("\nExit.\n");

       return;

       }

    send(sockfd, sendline, strlen(sendline),0);

 

    /* send message to server */ 

    while (getMessage(sendline, MAXDATASIZE, fp) != NULL) {

       send(sockfd, sendline, strlen(sendline),0);

 

       if ((numbytes = recv(sockfd, recvline, MAXDATASIZE,0)) == 0) {

          printf("Server terminated.\n");

          return;

          }

 

       recvline[numbytes]='\0';

       printf("Server Message: %s\n",recvline); /* it prints server's welcome message  */

 

       }

    printf("\nExit.\n");

    }

 

    char* getMessage(char* sendline,int len, FILE* fp)

    {

    printf("Input string to server:");

    return(fgets(sendline, MAXDATASIZE, fp));

    }

 

 

阅读(2082) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~