原创 select()函数实现并发服务器

2013-5-18 08:47 1191 21 22 分类: 消费电子

        自学嵌入式linux时间也不短了,但是作为一个三天打鱼两天晒网的人来说,我学习随意性很强,一般在工作之余看一点儿书、敲几行代码,进度也很慢。现在把总结的一些内容整理成博客,一方面跟大家共同分享一下学习过程,另一方面呢也督促一下自己努力学习!哈哈。下面进入正题,这篇博客的主题是select()函数实现并发服务器。下面直接上代码(带有注释的哦,全是我自己的理解,有误之处恳请各位大牛多多扶持),在代码的最后我用visio做了个简单的流程图,做的很粗糙,希望不会有碍观瞻!

         以下代码是select()函数实现并发服务器的程序代码,现对其作出解释:

#include

#include

#include

#include

#include

#include

#include

#include

 

#define  BACK_LOG 10

#define BUF_SIZE 1024

#define PORT 8000

 

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

{

       int sockfd;

     int connfd;

     int clifd;

     int ret_val;

      

     int max_fd;

     int i;

     int nready;

     int max_index;

     int len;

     socklen_t clilen;

     int port;

 

     struct sockaddr_in servaddr,cliaddr;

     int client[FD_SETSIZE];

     char buffer[BUF_SIZE];

 

     fd_set allset,rdset;

 

       struct timeval tv = {0, 0};    

 

     if(argc != 2)

       {

                 printf("Usage: echoserv ");

                 exit(1);

     }

     bzero(&servaddr,sizeof(struct sockaddr_in));

     servaddr.sin_family = AF_INET;

     servaddr.sin_addr.s_addr = INADDR_ANY;

       //   servaddr.sin_port = htons(PORT);

     servaddr.sin_port = htons(atoi(argv[1]));             // 端口号由程序运行时作为参数传入

  

     sockfd = socket(AF_INET, SOCK_STREAM, 0);              // 打开通讯端口

     if (sockfd == -1)

       {

                 perror("socket");

                 exit(1);

     }

 

     ret_val = bind(sockfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr));  //绑定服务器IP和端口

     if (ret_val == -1)  

       {

                 perror("bind");

                 exit(1);

     }

  

       ret_val = listen(sockfd, BACK_LOG);         // 将主动连接套接字变为被动连接套接字

     if (ret_val == -1)

       {

                 perror("listen");

                 exit(1);

     } 

     max_fd = sockfd;

 

     FD_ZERO(&allset);                                  // 清空描述符集

     FD_ZERO(&rdset);

     FD_SET(sockfd,&allset);                           // 将通讯端口描述符加入描述符集中

 

     for(i=0; i< FD_SETSIZE; i++)

                 client = -1;

     max_index = -1;

 

     for(;;)

       {

                 rdset = allset;

                 //nready = select(max_fd+1,&rdset,NULL,NULL,NULL);  // 以阻塞方式监听rdset描述符集中是否有可读的描述符

                 nready = select(max_fd+1,&rdset,NULL,NULL,&tv); // 以完全非阻塞方式监听rdset描述符集中是否有可读的描述符

            if(FD_ISSET(sockfd, &rdset))     // FD_ISSET用来检测描述符集中指定描述符状态是否发生了变化,在此用来检测通讯端口是否有新的请求连接

              {                  

                      clilen = sizeof(cliaddr);

                      connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &clilen);   // 为新建立的连接分配通讯描述符

                      if(connfd ==-1)

                     {

                           perror("accept");

                           continue;

                      }

                      for(i=0; i;>

                     {

                           if(client == -1)

                            {

                                       client = connfd;  // 填充客户端通讯描述符表

                                       break;

                           }

                      }

       

                      if(i == FD_SETSIZE)          // FD_SETSIZE宏是在哪里定义的?

                     {

                           printf("Too many client here!");

                           exit(1);

                      }

                      if(i > max_index)

                           max_index = i;

                      if(connfd > max_fd)

                           max_fd = connfd;

                      FD_SET(connfd,&allset);

 

                      if(--nready <=0)     // 完成对新建的客户端分配描述符之后重新跳select()监控新建立的客户端或者接收已建立客户端的数据发送请求

                            continue;       

                 }

            for (i=0; i<= max_index; i++)            // 程序运行到此处说明有客户端发送数据请求(select()函数以阻塞方式工作时)以轮询方式服务已建立的客户端

              {

                      if((clifd=client)< 0)

                            continue;

                      if(FD_ISSET(clifd,&rdset))  // 检查是哪个客户端发起的数据请求,并为服务

                     {

                           len = BUF_SIZE;

                           len = recv(clifd, buffer, len, 0);

                           if (len <= 0)

                            {

                                       close(clifd);

                                       FD_CLR(clifd,&allset);

                                       client = -1;

                           }

                            else             

                                       send(clifd,buffer,len,0); // 应用层协议在此实现 ,该范例仅原样返回接收到的字符串

                           if(--nready <=0)    

                                     break;

                       }//if

    

                  }//for  

     }//for

}

以下是我编写的程序流程图:

 

clip_image002.gif
附件中是程序源码和visio格式的程序流程图。

文章评论1条评论)

登录后参与讨论

用户1585841 2013-5-29 13:47

蓝牙消费品

用户1406868 2013-5-27 18:56

没有多线程也好意思叫并发?

用户1585841 2012-12-21 09:37

是,蓝牙模组用串口和你们的芯片通讯。

用户1674793 2012-12-10 16:35

需要制作蓝牙端在血压测量器上,通过蓝牙端发到iphone/pc上是么?

相关推荐阅读
462629051_256703759 2014-06-08 21:56
产品研发的一点想法
        产品研发的核心是产品,研发是为了实现产品,所以能够快速设计出稳定的产品才是研发的目的。通过对比自己身边的一些项目产生了一些想法,总体来说就是尽可能采用半导体厂商的最成熟方案尽可能和...
462629051_256703759 2014-03-01 12:34
LED子系统
        Linux驱动中已经将led驱动作为一个子系统来实现了,针对Tiny210采用通用IO口来控制led的情况,linux采用platform驱动来实现led子系统,因此我们可以通过l...
462629051_256703759 2014-02-27 22:47
git入门
15.1、安装git $sudo apt-get install git $sudo apt-get install git-core 更新git $git clone git:/...
462629051_256703759 2014-02-27 15:05
Vim + Ctags + Taglist组合
12.1、Ctags和Taglist插件的安装: 12.1.1、Ctags插件的安装:sudo apt-get install ctags 12.1.2、Taglist插件的安装:首先下载...
462629051_256703759 2013-09-23 15:57
改善电源负载瞬态响应性能的设计方法
        以前对电源芯片的理解停留在输出电压是否满足需求、输出电流是否满足负载等一些静态的参数上,但是后来发现即使这些参数满足要求所选用的电源芯片有可能还是不能满足负载瞬变时的波动,所以就查...
462629051_256703759 2013-09-05 14:33
MSP430两种串口升级方式对比
        早上收到网友咨询MSP430单片机串口升级问题的邮件,因为不是第一次收到这样的帮助请求,于是便把自己做过的两种串口升级方式做一对比希望对此问题感兴趣的工程师朋友可以从中受益,也希望...
我要评论
1
21
关闭 站长推荐上一条 /2 下一条