zoukankan      html  css  js  c++  java
  • select函数

    select函数:

      系统提供select函数来实现多路复用输入/输出模型。原型:

      #include <sys/time.h>

      #include <unistd.h>

      select函数:

      系统提供select函数来实现多路复用输入/输出模型。原型:

      #include <sys/time.h>

      #include <unistd.h>

      int select(int maxfd,fd_set *rdset,fd_set *wrset,fd_set *exset,struct timeval *timeout);

      参数maxfd是需要监视的最大的文件描述符值+1;rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集 合及异常文件描述符的集合。struct timeval结构用于描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生则函数返回,返回值为0。

      FD_ZERO,FD_SET,FD_CLR,FD_ISSET: 参数maxfd是需要监视的最大的文件描述符值+1;rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集 合及异常文件描述符的集合。struct timeval结构用于描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生则函数返回,返回值为0。

      FD_ZERO,FD_SET,FD_CLR,FD_ISSET:

      FD_ZERO(fd_set *fdset);将指定的文件描述符集清空,在对文件描述符集合进行设置前,必须对其进行初始化,如果不清空,由于在系统分配内存空间后,通常并不作清空处理,所以结果是不可知的。

      FD_SET(fd_set *fdset);用于在文件描述符集合中增加一个新的文件描述符。

      FD_CLR(fd_set *fdset);用于在文件描述符集合中删除一个文件描述符。

      FD_ISSET(int fd,fd_set *fdset);用于测试指定的文件描述符是否在该集合中。

      struct timeval结构:

      struct timeval{

      long tv_sec;//second

      long tv_usec;//minisecond

      }

      timeout设置情况:

      null:select将一直被阻塞,直到某个文件描述符上发生了事件。

      0:仅检测描述符集合的状态,然后立即返回,并不等待外部事件的发生。

      特定的时间值:如果在指定的时间段里没有事件发生,select将超时返回。

      --

      ('fd_set') 是一组文件描述符(fd)的集合。由于fd_set类型的长度在不同平台上不同,因此应该用一组标准的宏定义来处理此类变量:

      fd_set set; FD_ZERO(&set); /* 将set清零 */ FD_SET(fd, &set); /* 将fd加入set */ FD_CLR(fd, &set); /* 将fd从set中清除 */ FD_ISSET(fd, &set); /* 如果fd在set中则真 */

      在 过去,一个fd_set通常只能包含少于等于32个文件描述符,因为fd_set其实只用了一个int的比特矢量来实现,在大多数情况下,检查 fd_set能包括任意值的文件描述符是系统的责任,但确定你的fd_set到底能放多少有时你应该检查/修改宏FD_SETSIZE的值。*这个值是系 统相关的*,同时检查你的系统中的select() 的man手册。有一些系统对多于1024个文件描述符的支持有问题。

      多路复用的方式是真正实用的服务器程序,非多路复用的网络程序只能作为学习或着陪测的角色。本文说下个人

      接触过的多路复用函数:select/poll/epoll/port。kqueue的*nix系统没接触过,估计熟悉了上面

      四种,kqueue也只是需要熟悉一下而已。

      一、select模型

      select原型: int select(int n ,fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

      其中参数n表示监控的所有fd中最大值+1。

      和select模型紧密结合的四个宏,含义不解释了:

      FD_CLR(int fd, fd_set *set);

      FD_ISSET(int fd, fd_set *set);

      FD_SET(int fd, fd_set *set);

      FD_ZERO(fd_set *set);

      理解select模型的关键在于理解fd_set,为说明方便,取fd_set长度为1字节,fd_set中的每一bit可以对应一个文件描述符fd。则1字节长的fd_set最大可以对应8个fd。

      (1)执行fd_set set; FD_ZERO(&set);则set用位表示是0000,0000。

      (2)若fd=5,执行FD_SET(fd,&set);后set变为0001,0000(第5位置为1)

      (3)若再加入fd=2,fd=1,则set变为0001,0011

      (4)执行select(6,&set,0,0,0)阻塞等待

      (5)若fd=1,fd=2上都发生可读事件,则select返回,此时set变为0000,0011。注意:没有事件发生的fd=5被清空。

      基于上面的讨论,可以轻松得出select模型的特点:

      (1)可监控的文件描述符个数取决与sizeof(fd_set)的值。我这边服务 器上sizeof(fd_set)=512,每bit表示一个文件描述符,则我服务器上支持的最大文件描述符是512*8=4096。据说可调,另有说虽 然可调,但调整上限受于编译内核时的变量值。本人对调整fd_set的大小不太感兴趣,参考http://www.cppblog.com /CppExplore/archive/2008/03/21/45061.html中的模型2(1)可以有效突破select可监控的文件描述符上 限。

      (2)将fd加入select监控集的同时,还要再使用一个数据结构array保存放到select监控集中的fd,一是用于再select 返回后,array作为源数据和fd_set进行FD_ISSET判断。二是select返回后会把以前加入的但并无事件发生的fd清空,则每次开始 select前都要重新从array取得fd逐一加入(FD_ZERO最先),扫描array的同时取得fd最大值maxfd,用于select的第一个 参数。

      (3)可见select模型必须在select前循环array(加fd,取maxfd),select返回后循环array(FD_ISSET判断是否有时间发生)。

      下面给一个伪码说明基本select模型的服务器模型:

      array[slect_len];

      nSock=0;

      array[nSock++]=listen_fd;(之前listen port已绑定并listen)

      maxfd=listen_fd;

      while{

      FD_ZERO(&set);

      foreach (fd in array)

      {

      fd大于maxfd,则maxfd=fd

      FD_SET(fd,&set)

      }

      res=select(maxfd+1,&set,0,0,0);

      if(FD_ISSET(listen_fd,&set))

      {

      newfd=accept(listen_fd);

      array[nsock++]=newfd;

      if(--res<=0) continue

      }

      foreach 下标1开始 (fd in array)

      {

      if(FD_ISSET(fd,&tyle="COLOR: #ff0000">set))

      执行读等相关操作

      如果错误或者关闭,则要删除该fd,将array中相应位置和最后一个元素互换就好,nsock减一

      if(--res<=0) continue

      }

      }

      服务器端代码:

      引用

      #include <sys/types.h>

      #include <sys/socket.h>

      #include <stdio.h>

      #include <netinet/in.h>

      #include <sys/time.h>

      #include <sys/ioctl.h>

      #include <unistd.h>

      #include <stdlib.h>

      int main()

      {

      int server_sockfd, client_sockfd;

      int server_len, client_len;

      struct sockaddr_in server_address;

      struct sockaddr_in client_address;

      int result;

      fd_set readfds, testfds;

      /*创建套接字:IPv4, tcp流套接字*/

      server_sockfd = socket(AF_INET, SOCK_STREAM, 0);

      server_address.sin_family = AF_INET;

      /*INADDR_ANY代表本机IP,htonl将其转换为网络字节顺序(大端模式)*/

      server_address.sin_addr.s_addr = htonl(INADDR_ANY);

      server_address.sin_port = htons(9734);

      server_len = sizeof(server_address);

      /*将端口与套接字绑定*/

      bind(server_sockfd, (struct sockaddr *)&server_address, server_len);

      /*监听,可接受5个连接请求*/

      listen(server_sockfd, 5);

      FD_ZERO(&readfds);

      FD_SET(server_sockfd, &readfds);

      /*等待客户端请求*/

      while(1) {

      char ch;

      int  fd;

      int  nread;

      testfds = readfds;

      /*服务器在select后等待客户端的请求(服务器阻塞)*/

      printf("server waiting/n");

      result = select(FD_SETSIZE, &testfds, (fd_set *)0,

      (fd_set *)0, (struct timeval *)0);

      if (result < 1) {

      perror("server");

      exit(1);

      }

      /*轮询,实际程序不使用这种极度耗时的方法*/

      for (fd = 0; fd < FD_SETSIZE; fd++) {

      if (FD_ISSET(fd, &testfds)) {

      if (fd == server_sockfd) {

      client_len = sizeof(client_address);

      client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address,

      &client_len);                    /*接收客户端连接请求,并返回连接套接字用于收发数据*/

      FD_SET(client_sockfd, &readfds);    /*需要监视发来请求的客户端*/

      printf("adding client on fd %d/n", client_sockfd);

      } else {                                                           /*客户端发生“状况”*/

      ioctl(fd, FIONREAD, &nread);

      if (nread == 0) {

      close(fd);                                        /*读取不到任何内容,关闭与客户端的连接套接字*/

      FD_CLR(fd, &readfds);              /*清除客户端套接字描述符,不再对其"关注"*/

      printf("removing client on fd %d/n", fd);

      } else {

      read(fd, &ch, 1);

      sleep(5);

      printf("serving client on fd %d/n", fd);

      ch++;

      write(fd, &ch, 1);

      }

      }

      }

      }

      }

      }

      例子2

      #include <stdio.h>

      #include <stdlib.h>

      #include <unistd.h>

      #include <errno.h>

      #include <string.h>

      #include <sys/types.h>

      #include <sys/socket.h>

      #include <netinet/in.h>

      #include <arpa/inet.h>

      #define MYPORT 1234    // the port users will be connecting to

      #define BACKLOG 5     // how many pending connections queue will hold

      #define BUF_SIZE 200

      int fd_A[BACKLOG];    // accepted connection fd

      int conn_amount;    // current connection amount

      void showclient()

      {

      int i;

      printf("client amount: %d/n", conn_amount);

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

      {

      printf("[%d]:%d  ", i, fd_A[i]);

      }

      printf("/n/n");

      }

      int main(void)

      {

      int sock_fd, new_fd;  // listen on sock_fd, new connection on new_fd

      struct sockaddr_in server_addr;    // server address information

      struct sockaddr_in client_addr; // connector's address information

      socklen_t sin_size;

      int yes = 1;

      char buf[BUF_SIZE];

      int ret;

      int i;

      if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)

      {

      perror("socket");

      exit(1);

      }

      if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)

      {

      perror("setsockopt");

      exit(1);

      }

      server_addr.sin_family = AF_INET;         // host byte order

      server_addr.sin_port = htons(MYPORT);     // short, network byte order

      server_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP

      memset(server_addr.sin_zero, '/0', sizeof(server_addr.sin_zero));

      if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)

      {

      perror("bind");

      exit(1);

      }

      if (listen(sock_fd, BACKLOG) == -1)

      {

      perror("listen");

      exit(1);

      }

      printf("listen port %d/n", MYPORT);

      fd_set fdsr;

      int maxsock;

      struct timeval tv;

      conn_amount = 0;

      sin_size = sizeof(client_addr);

      maxsock = sock_fd;

      while (1)

      {

      // initialize file descriptor set

      FD_ZERO(&fdsr);

      FD_SET(sock_fd, &fdsr);

      // timeout setting

      tv.tv_sec = 30;

      tv.tv_usec = 0;

      // add active connection to fd set

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

      {

      if (fd_A[i] != 0)

      {

      FD_SET(fd_A[i], &fdsr);

      }

      }

      ret = select(maxsock + 1, &fdsr, NULL, NULL, &tv);

      if (ret < 0)

      {

      perror("select");

      break;

      } else if (ret == 0)

      {

      printf("timeout/n");

      continue;

      }

      // check every fd in the set

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

      {

      if (FD_ISSET(fd_A[i], &fdsr))

      {

      ret = recv(fd_A[i], buf, sizeof(buf), 0);

      if (ret <= 0)

      {        // client close

      printf("client[%d] close/n", i);

      close(fd_A[i]);

      FD_CLR(fd_A[i], &fdsr);

      fd_A[i] = 0;

      }

      else

      {        // receive data

      if (ret < BUF_SIZE)

      memset(&buf[ret], '/0', 1);

      printf("client[%d] send:%s/n", i, buf);

      }

      }

      }

      // check whether a new connection comes

      if (FD_ISSET(sock_fd, &fdsr))

      {

      new_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &sin_size);

      if (new_fd <= 0)

      {

      perror("accept");

      continue;

      }

      // add to fd queue

      if (conn_amount < BACKLOG)

      {

      fd_A[conn_amount++] = new_fd;

      printf("new connection client[%d] %s:%d/n", conn_amount,

      inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

      if (new_fd > maxsock)

      maxsock = new_fd;

      }

      else

      {

      printf("max connections arrive, exit/n");

      send(new_fd, "bye", 4, 0);

      close(new_fd);

      break;

      }

      }

      showclient();

      }

      // close other connections

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

      {

      if (fd_A[i] != 0)

      {

      close(fd_A[i]);

      }

      }

      exit(0);

      }

    select函数:

      系统提供select函数来实现多路复用输入/输出模型。原型:

      #include <sys/time.h>

      #include <unistd.h>

      select函数:

      系统提供select函数来实现多路复用输入/输出模型。原型:

      #include <sys/time.h>

      #include <unistd.h>

      int select(int maxfd,fd_set *rdset,fd_set *wrset,fd_set *exset,struct timeval *timeout);

      参数maxfd是需要监视的最大的文件描述符值+1;rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集 合及异常文件描述符的集合。struct timeval结构用于描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生则函数返回,返回值为0。

      FD_ZERO,FD_SET,FD_CLR,FD_ISSET: 参数maxfd是需要监视的最大的文件描述符值+1;rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集 合及异常文件描述符的集合。struct timeval结构用于描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生则函数返回,返回值为0。

      FD_ZERO,FD_SET,FD_CLR,FD_ISSET:

      FD_ZERO(fd_set *fdset);将指定的文件描述符集清空,在对文件描述符集合进行设置前,必须对其进行初始化,如果不清空,由于在系统分配内存空间后,通常并不作清空处理,所以结果是不可知的。

      FD_SET(fd_set *fdset);用于在文件描述符集合中增加一个新的文件描述符。

      FD_CLR(fd_set *fdset);用于在文件描述符集合中删除一个文件描述符。

      FD_ISSET(int fd,fd_set *fdset);用于测试指定的文件描述符是否在该集合中。

      struct timeval结构:

      struct timeval{

      long tv_sec;//second

      long tv_usec;//minisecond

      }

      timeout设置情况:

      null:select将一直被阻塞,直到某个文件描述符上发生了事件。

      0:仅检测描述符集合的状态,然后立即返回,并不等待外部事件的发生。

      特定的时间值:如果在指定的时间段里没有事件发生,select将超时返回。

      --

      ('fd_set') 是一组文件描述符(fd)的集合。由于fd_set类型的长度在不同平台上不同,因此应该用一组标准的宏定义来处理此类变量:

      fd_set set; FD_ZERO(&set); /* 将set清零 */ FD_SET(fd, &set); /* 将fd加入set */ FD_CLR(fd, &set); /* 将fd从set中清除 */ FD_ISSET(fd, &set); /* 如果fd在set中则真 */

      在 过去,一个fd_set通常只能包含少于等于32个文件描述符,因为fd_set其实只用了一个int的比特矢量来实现,在大多数情况下,检查 fd_set能包括任意值的文件描述符是系统的责任,但确定你的fd_set到底能放多少有时你应该检查/修改宏FD_SETSIZE的值。*这个值是系 统相关的*,同时检查你的系统中的select() 的man手册。有一些系统对多于1024个文件描述符的支持有问题。

      多路复用的方式是真正实用的服务器程序,非多路复用的网络程序只能作为学习或着陪测的角色。本文说下个人

      接触过的多路复用函数:select/poll/epoll/port。kqueue的*nix系统没接触过,估计熟悉了上面

      四种,kqueue也只是需要熟悉一下而已。

      一、select模型

      select原型: int select(int n ,fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

      其中参数n表示监控的所有fd中最大值+1。

      和select模型紧密结合的四个宏,含义不解释了:

      FD_CLR(int fd, fd_set *set);

      FD_ISSET(int fd, fd_set *set);

      FD_SET(int fd, fd_set *set);

      FD_ZERO(fd_set *set);

      理解select模型的关键在于理解fd_set,为说明方便,取fd_set长度为1字节,fd_set中的每一bit可以对应一个文件描述符fd。则1字节长的fd_set最大可以对应8个fd。

      (1)执行fd_set set; FD_ZERO(&set);则set用位表示是0000,0000。

      (2)若fd=5,执行FD_SET(fd,&set);后set变为0001,0000(第5位置为1)

      (3)若再加入fd=2,fd=1,则set变为0001,0011

      (4)执行select(6,&set,0,0,0)阻塞等待

      (5)若fd=1,fd=2上都发生可读事件,则select返回,此时set变为0000,0011。注意:没有事件发生的fd=5被清空。

      基于上面的讨论,可以轻松得出select模型的特点:

      (1)可监控的文件描述符个数取决与sizeof(fd_set)的值。我这边服务 器上sizeof(fd_set)=512,每bit表示一个文件描述符,则我服务器上支持的最大文件描述符是512*8=4096。据说可调,另有说虽 然可调,但调整上限受于编译内核时的变量值。本人对调整fd_set的大小不太感兴趣,参考http://www.cppblog.com /CppExplore/archive/2008/03/21/45061.html中的模型2(1)可以有效突破select可监控的文件描述符上 限。

      (2)将fd加入select监控集的同时,还要再使用一个数据结构array保存放到select监控集中的fd,一是用于再select 返回后,array作为源数据和fd_set进行FD_ISSET判断。二是select返回后会把以前加入的但并无事件发生的fd清空,则每次开始 select前都要重新从array取得fd逐一加入(FD_ZERO最先),扫描array的同时取得fd最大值maxfd,用于select的第一个 参数。

      (3)可见select模型必须在select前循环array(加fd,取maxfd),select返回后循环array(FD_ISSET判断是否有时间发生)。

      下面给一个伪码说明基本select模型的服务器模型:

      array[slect_len];

      nSock=0;

      array[nSock++]=listen_fd;(之前listen port已绑定并listen)

      maxfd=listen_fd;

      while{

      FD_ZERO(&set);

      foreach (fd in array)

      {

      fd大于maxfd,则maxfd=fd

      FD_SET(fd,&set)

      }

      res=select(maxfd+1,&set,0,0,0);

      if(FD_ISSET(listen_fd,&set))

      {

      newfd=accept(listen_fd);

      array[nsock++]=newfd;

      if(--res<=0) continue

      }

      foreach 下标1开始 (fd in array)

      {

      if(FD_ISSET(fd,&tyle="COLOR: #ff0000">set))

      执行读等相关操作

      如果错误或者关闭,则要删除该fd,将array中相应位置和最后一个元素互换就好,nsock减一

      if(--res<=0) continue

      }

      }

      服务器端代码:

      引用

      #include <sys/types.h>

      #include <sys/socket.h>

      #include <stdio.h>

      #include <netinet/in.h>

      #include <sys/time.h>

      #include <sys/ioctl.h>

      #include <unistd.h>

      #include <stdlib.h>

      int main()

      {

      int server_sockfd, client_sockfd;

      int server_len, client_len;

      struct sockaddr_in server_address;

      struct sockaddr_in client_address;

      int result;

      fd_set readfds, testfds;

      /*创建套接字:IPv4, tcp流套接字*/

      server_sockfd = socket(AF_INET, SOCK_STREAM, 0);

      server_address.sin_family = AF_INET;

      /*INADDR_ANY代表本机IP,htonl将其转换为网络字节顺序(大端模式)*/

      server_address.sin_addr.s_addr = htonl(INADDR_ANY);

      server_address.sin_port = htons(9734);

      server_len = sizeof(server_address);

      /*将端口与套接字绑定*/

      bind(server_sockfd, (struct sockaddr *)&server_address, server_len);

      /*监听,可接受5个连接请求*/

      listen(server_sockfd, 5);

      FD_ZERO(&readfds);

      FD_SET(server_sockfd, &readfds);

      /*等待客户端请求*/

      while(1) {

      char ch;

      int  fd;

      int  nread;

      testfds = readfds;

      /*服务器在select后等待客户端的请求(服务器阻塞)*/

      printf("server waiting/n");

      result = select(FD_SETSIZE, &testfds, (fd_set *)0,

      (fd_set *)0, (struct timeval *)0);

      if (result < 1) {

      perror("server");

      exit(1);

      }

      /*轮询,实际程序不使用这种极度耗时的方法*/

      for (fd = 0; fd < FD_SETSIZE; fd++) {

      if (FD_ISSET(fd, &testfds)) {

      if (fd == server_sockfd) {

      client_len = sizeof(client_address);

      client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address,

      &client_len);                    /*接收客户端连接请求,并返回连接套接字用于收发数据*/

      FD_SET(client_sockfd, &readfds);    /*需要监视发来请求的客户端*/

      printf("adding client on fd %d/n", client_sockfd);

      } else {                                                           /*客户端发生“状况”*/

      ioctl(fd, FIONREAD, &nread);

      if (nread == 0) {

      close(fd);                                        /*读取不到任何内容,关闭与客户端的连接套接字*/

      FD_CLR(fd, &readfds);              /*清除客户端套接字描述符,不再对其"关注"*/

      printf("removing client on fd %d/n", fd);

      } else {

      read(fd, &ch, 1);

      sleep(5);

      printf("serving client on fd %d/n", fd);

      ch++;

      write(fd, &ch, 1);

      }

      }

      }

      }

      }

      }

      例子2

      #include <stdio.h>

      #include <stdlib.h>

      #include <unistd.h>

      #include <errno.h>

      #include <string.h>

      #include <sys/types.h>

      #include <sys/socket.h>

      #include <netinet/in.h>

      #include <arpa/inet.h>

      #define MYPORT 1234    // the port users will be connecting to

      #define BACKLOG 5     // how many pending connections queue will hold

      #define BUF_SIZE 200

      int fd_A[BACKLOG];    // accepted connection fd

      int conn_amount;    // current connection amount

      void showclient()

      {

      int i;

      printf("client amount: %d/n", conn_amount);

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

      {

      printf("[%d]:%d  ", i, fd_A[i]);

      }

      printf("/n/n");

      }

      int main(void)

      {

      int sock_fd, new_fd;  // listen on sock_fd, new connection on new_fd

      struct sockaddr_in server_addr;    // server address information

      struct sockaddr_in client_addr; // connector's address information

      socklen_t sin_size;

      int yes = 1;

      char buf[BUF_SIZE];

      int ret;

      int i;

      if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)

      {

      perror("socket");

      exit(1);

      }

      if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)

      {

      perror("setsockopt");

      exit(1);

      }

      server_addr.sin_family = AF_INET;         // host byte order

      server_addr.sin_port = htons(MYPORT);     // short, network byte order

      server_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP

      memset(server_addr.sin_zero, '/0', sizeof(server_addr.sin_zero));

      if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)

      {

      perror("bind");

      exit(1);

      }

      if (listen(sock_fd, BACKLOG) == -1)

      {

      perror("listen");

      exit(1);

      }

      printf("listen port %d/n", MYPORT);

      fd_set fdsr;

      int maxsock;

      struct timeval tv;

      conn_amount = 0;

      sin_size = sizeof(client_addr);

      maxsock = sock_fd;

      while (1)

      {

      // initialize file descriptor set

      FD_ZERO(&fdsr);

      FD_SET(sock_fd, &fdsr);

      // timeout setting

      tv.tv_sec = 30;

      tv.tv_usec = 0;

      // add active connection to fd set

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

      {

      if (fd_A[i] != 0)

      {

      FD_SET(fd_A[i], &fdsr);

      }

      }

      ret = select(maxsock + 1, &fdsr, NULL, NULL, &tv);

      if (ret < 0)

      {

      perror("select");

      break;

      } else if (ret == 0)

      {

      printf("timeout/n");

      continue;

      }

      // check every fd in the set

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

      {

      if (FD_ISSET(fd_A[i], &fdsr))

      {

      ret = recv(fd_A[i], buf, sizeof(buf), 0);

      if (ret <= 0)

      {        // client close

      printf("client[%d] close/n", i);

      close(fd_A[i]);

      FD_CLR(fd_A[i], &fdsr);

      fd_A[i] = 0;

      }

      else

      {        // receive data

      if (ret < BUF_SIZE)

      memset(&buf[ret], '/0', 1);

      printf("client[%d] send:%s/n", i, buf);

      }

      }

      }

      // check whether a new connection comes

      if (FD_ISSET(sock_fd, &fdsr))

      {

      new_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &sin_size);

      if (new_fd <= 0)

      {

      perror("accept");

      continue;

      }

      // add to fd queue

      if (conn_amount < BACKLOG)

      {

      fd_A[conn_amount++] = new_fd;

      printf("new connection client[%d] %s:%d/n", conn_amount,

      inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

      if (new_fd > maxsock)

      maxsock = new_fd;

      }

      else

      {

      printf("max connections arrive, exit/n");

      send(new_fd, "bye", 4, 0);

      close(new_fd);

      break;

      }

      }

      showclient();

      }

      // close other connections

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

      {

      if (fd_A[i] != 0)

      {

      close(fd_A[i]);

      }

      }

      exit(0);

      }

    select函数:
      系统提供select函数来实现多路复用输入/输出模型。原型:
      #include <sys/time.h>
      #include <unistd.h>
      select函数:
      系统提供select函数来实现多路复用输入/输出模型。原型:
      #include <sys/time.h>
      #include <unistd.h>
      int select(int maxfd,fd_set *rdset,fd_set *wrset,fd_set *exset,struct timeval *timeout);
      参数maxfd是需要监视的最大的文件描述符值+1;rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集 合及异常文件描述符的集合。struct timeval结构用于描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生则函数返回,返回值为0。
      FD_ZERO,FD_SET,FD_CLR,FD_ISSET: 参数maxfd是需要监视的最大的文件描述符值+1;rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集 合及异常文件描述符的集合。struct timeval结构用于描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生则函数返回,返回值为0。
      FD_ZERO,FD_SET,FD_CLR,FD_ISSET:
      FD_ZERO(fd_set *fdset);将指定的文件描述符集清空,在对文件描述符集合进行设置前,必须对其进行初始化,如果不清空,由于在系统分配内存空间后,通常并不作清空处理,所以结果是不可知的。
      FD_SET(fd_set *fdset);用于在文件描述符集合中增加一个新的文件描述符。
      FD_CLR(fd_set *fdset);用于在文件描述符集合中删除一个文件描述符。
      FD_ISSET(int fd,fd_set *fdset);用于测试指定的文件描述符是否在该集合中。
      struct timeval结构:
      struct timeval{
      long tv_sec;//second
      long tv_usec;//minisecond
      }
      timeout设置情况:
      null:select将一直被阻塞,直到某个文件描述符上发生了事件。
      0:仅检测描述符集合的状态,然后立即返回,并不等待外部事件的发生。
      特定的时间值:如果在指定的时间段里没有事件发生,select将超时返回。
      --
      ('fd_set') 是一组文件描述符(fd)的集合。由于fd_set类型的长度在不同平台上不同,因此应该用一组标准的宏定义来处理此类变量:
      fd_set set; FD_ZERO(&set); /* 将set清零 */ FD_SET(fd, &set); /* 将fd加入set */ FD_CLR(fd, &set); /* 将fd从set中清除 */ FD_ISSET(fd, &set); /* 如果fd在set中则真 */
      在 过去,一个fd_set通常只能包含少于等于32个文件描述符,因为fd_set其实只用了一个int的比特矢量来实现,在大多数情况下,检查 fd_set能包括任意值的文件描述符是系统的责任,但确定你的fd_set到底能放多少有时你应该检查/修改宏FD_SETSIZE的值。*这个值是系 统相关的*,同时检查你的系统中的select() 的man手册。有一些系统对多于1024个文件描述符的支持有问题。
      多路复用的方式是真正实用的服务器程序,非多路复用的网络程序只能作为学习或着陪测的角色。本文说下个人
      接触过的多路复用函数:select/poll/epoll/port。kqueue的*nix系统没接触过,估计熟悉了上面
      四种,kqueue也只是需要熟悉一下而已。
      一、select模型
      select原型: int select(int n ,fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
      其中参数n表示监控的所有fd中最大值+1。
      和select模型紧密结合的四个宏,含义不解释了:
      FD_CLR(int fd, fd_set *set);
      FD_ISSET(int fd, fd_set *set);
      FD_SET(int fd, fd_set *set);
      FD_ZERO(fd_set *set);
      理解select模型的关键在于理解fd_set,为说明方便,取fd_set长度为1字节,fd_set中的每一bit可以对应一个文件描述符fd。则1字节长的fd_set最大可以对应8个fd。
      (1)执行fd_set set; FD_ZERO(&set);则set用位表示是0000,0000。
      (2)若fd=5,执行FD_SET(fd,&set);后set变为0001,0000(第5位置为1)
      (3)若再加入fd=2,fd=1,则set变为0001,0011
      (4)执行select(6,&set,0,0,0)阻塞等待
      (5)若fd=1,fd=2上都发生可读事件,则select返回,此时set变为0000,0011。注意:没有事件发生的fd=5被清空。
      基于上面的讨论,可以轻松得出select模型的特点:
      (1)可监控的文件描述符个数取决与sizeof(fd_set)的值。我这边服务 器上sizeof(fd_set)=512,每bit表示一个文件描述符,则我服务器上支持的最大文件描述符是512*8=4096。据说可调,另有说虽 然可调,但调整上限受于编译内核时的变量值。本人对调整fd_set的大小不太感兴趣,参考http://www.cppblog.com /CppExplore/archive/2008/03/21/45061.html中的模型2(1)可以有效突破select可监控的文件描述符上 限。
      (2)将fd加入select监控集的同时,还要再使用一个数据结构array保存放到select监控集中的fd,一是用于再select 返回后,array作为源数据和fd_set进行FD_ISSET判断。二是select返回后会把以前加入的但并无事件发生的fd清空,则每次开始 select前都要重新从array取得fd逐一加入(FD_ZERO最先),扫描array的同时取得fd最大值maxfd,用于select的第一个 参数。
      (3)可见select模型必须在select前循环array(加fd,取maxfd),select返回后循环array(FD_ISSET判断是否有时间发生)。
      下面给一个伪码说明基本select模型的服务器模型:
      array[slect_len];
      nSock=0;
      array[nSock++]=listen_fd;(之前listen port已绑定并listen)
      maxfd=listen_fd;
      while{
      FD_ZERO(&set);
      foreach (fd in array)
      {
      fd大于maxfd,则maxfd=fd
      FD_SET(fd,&set)
      }
      res=select(maxfd+1,&set,0,0,0);
      if(FD_ISSET(listen_fd,&set))
      {
      newfd=accept(listen_fd);
      array[nsock++]=newfd;
      if(--res<=0) continue
      }
      foreach 下标1开始 (fd in array)
      {
      if(FD_ISSET(fd,&tyle="COLOR: #ff0000">set))
      执行读等相关操作
      如果错误或者关闭,则要删除该fd,将array中相应位置和最后一个元素互换就好,nsock减一
      if(--res<=0) continue
      }
      }
     
     
     
      服务器端代码:
      引用
      #include <sys/types.h>
      #include <sys/socket.h>
      #include <stdio.h>
      #include <netinet/in.h>
      #include <sys/time.h>
      #include <sys/ioctl.h>
      #include <unistd.h>
      #include <stdlib.h>
      int main()
      {
      int server_sockfd, client_sockfd;
      int server_len, client_len;
      struct sockaddr_in server_address;
      struct sockaddr_in client_address;
      int result;
      fd_set readfds, testfds;
      /*创建套接字:IPv4, tcp流套接字*/
      server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
      server_address.sin_family = AF_INET;
      /*INADDR_ANY代表本机IP,htonl将其转换为网络字节顺序(大端模式)*/
      server_address.sin_addr.s_addr = htonl(INADDR_ANY);
      server_address.sin_port = htons(9734);
      server_len = sizeof(server_address);
      /*将端口与套接字绑定*/
      bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
      /*监听,可接受5个连接请求*/
      listen(server_sockfd, 5);
      FD_ZERO(&readfds);
      FD_SET(server_sockfd, &readfds);
      /*等待客户端请求*/
      while(1) {
      char ch;
      int  fd;
      int  nread;
      testfds = readfds;
      /*服务器在select后等待客户端的请求(服务器阻塞)*/
      printf("server waiting/n");
      result = select(FD_SETSIZE, &testfds, (fd_set *)0,
      (fd_set *)0, (struct timeval *)0);
      if (result < 1) {
      perror("server");
      exit(1);
      }
      /*轮询,实际程序不使用这种极度耗时的方法*/
      for (fd = 0; fd < FD_SETSIZE; fd++) {
      if (FD_ISSET(fd, &testfds)) {
      if (fd == server_sockfd) {
      client_len = sizeof(client_address);
      client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address,
      &client_len);                    /*接收客户端连接请求,并返回连接套接字用于收发数据*/
      FD_SET(client_sockfd, &readfds);    /*需要监视发来请求的客户端*/
      printf("adding client on fd %d/n", client_sockfd);
      } else {                                                           /*客户端发生“状况”*/
      ioctl(fd, FIONREAD, &nread);
      if (nread == 0) {
      close(fd);                                        /*读取不到任何内容,关闭与客户端的连接套接字*/
      FD_CLR(fd, &readfds);              /*清除客户端套接字描述符,不再对其"关注"*/
      printf("removing client on fd %d/n", fd);
      } else {
      read(fd, &ch, 1);
      sleep(5);
      printf("serving client on fd %d/n", fd);
      ch++;
      write(fd, &ch, 1);
      }
      }
      }
      }
      }
      }
     
     
      例子2
      #include <stdio.h>
      #include <stdlib.h>
      #include <unistd.h>
      #include <errno.h>
      #include <string.h>
      #include <sys/types.h>
      #include <sys/socket.h>
      #include <netinet/in.h>
      #include <arpa/inet.h>
      #define MYPORT 1234    // the port users will be connecting to
      #define BACKLOG 5     // how many pending connections queue will hold
      #define BUF_SIZE 200
      int fd_A[BACKLOG];    // accepted connection fd
      int conn_amount;    // current connection amount
      void showclient()
      {
      int i;
      printf("client amount: %d/n", conn_amount);
      for (i = 0; i < BACKLOG; i++)
      {
      printf("[%d]:%d  ", i, fd_A[i]);
      }
      printf("/n/n");
      }
      int main(void)
      {
      int sock_fd, new_fd;  // listen on sock_fd, new connection on new_fd
      struct sockaddr_in server_addr;    // server address information
      struct sockaddr_in client_addr; // connector's address information
      socklen_t sin_size;
      int yes = 1;
      char buf[BUF_SIZE];
      int ret;
      int i;
      if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
      {
      perror("socket");
      exit(1);
      }
      if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
      {
      perror("setsockopt");
      exit(1);
      }
      server_addr.sin_family = AF_INET;         // host byte order
      server_addr.sin_port = htons(MYPORT);     // short, network byte order
      server_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
      memset(server_addr.sin_zero, '/0', sizeof(server_addr.sin_zero));
      if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)
      {
      perror("bind");
      exit(1);
      }
      if (listen(sock_fd, BACKLOG) == -1)
      {
      perror("listen");
      exit(1);
      }
      printf("listen port %d/n", MYPORT);
      fd_set fdsr;
      int maxsock;
      struct timeval tv;
      conn_amount = 0;
      sin_size = sizeof(client_addr);
      maxsock = sock_fd;
      while (1)
      {
      // initialize file descriptor set
      FD_ZERO(&fdsr);
      FD_SET(sock_fd, &fdsr);
      // timeout setting
      tv.tv_sec = 30;
      tv.tv_usec = 0;
      // add active connection to fd set
      for (i = 0; i < BACKLOG; i++)
      {
      if (fd_A[i] != 0)
      {
      FD_SET(fd_A[i], &fdsr);
      }
      }
     
      ret = select(maxsock + 1, &fdsr, NULL, NULL, &tv);
      if (ret < 0)
      {
      perror("select");
      break;
      } else if (ret == 0)
      {
      printf("timeout/n");
      continue;
      }
      // check every fd in the set
      for (i = 0; i < conn_amount; i++)
      {
      if (FD_ISSET(fd_A[i], &fdsr))
      {
      ret = recv(fd_A[i], buf, sizeof(buf), 0);
      if (ret <= 0)
      {        // client close
      printf("client[%d] close/n", i);
      close(fd_A[i]);
      FD_CLR(fd_A[i], &fdsr);
      fd_A[i] = 0;
      }
      else
      {        // receive data
      if (ret < BUF_SIZE)
      memset(&buf[ret], '/0', 1);
      printf("client[%d] send:%s/n", i, buf);
      }
      }
      }
      // check whether a new connection comes
      if (FD_ISSET(sock_fd, &fdsr))
      {
      new_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &sin_size);
      if (new_fd <= 0)
      {
      perror("accept");
      continue;
      }
      // add to fd queue
      if (conn_amount < BACKLOG)
      {
      fd_A[conn_amount++] = new_fd;
      printf("new connection client[%d] %s:%d/n", conn_amount,
      inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
      if (new_fd > maxsock)
      maxsock = new_fd;
      }
      else
      {
      printf("max connections arrive, exit/n");
      send(new_fd, "bye", 4, 0);
      close(new_fd);
      break;
      }
      }
      showclient();
      }
      // close other connections
      for (i = 0; i < BACKLOG; i++)
      {
      if (fd_A[i] != 0)
      {
      close(fd_A[i]);
      }
      }
      exit(0);
      }

    select函数:

      系统提供select函数来实现多路复用输入/输出模型。原型:

      #include <sys/time.h>

      #include <unistd.h>

      select函数:

      系统提供select函数来实现多路复用输入/输出模型。原型:

      #include <sys/time.h>

      #include <unistd.h>

      int select(int maxfd,fd_set *rdset,fd_set *wrset,fd_set *exset,struct timeval *timeout);

      参数maxfd是需要监视的最大的文件描述符值+1;rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集 合及异常文件描述符的集合。struct timeval结构用于描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生则函数返回,返回值为0。

      FD_ZERO,FD_SET,FD_CLR,FD_ISSET: 参数maxfd是需要监视的最大的文件描述符值+1;rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集 合及异常文件描述符的集合。struct timeval结构用于描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生则函数返回,返回值为0。

      FD_ZERO,FD_SET,FD_CLR,FD_ISSET:

      FD_ZERO(fd_set *fdset);将指定的文件描述符集清空,在对文件描述符集合进行设置前,必须对其进行初始化,如果不清空,由于在系统分配内存空间后,通常并不作清空处理,所以结果是不可知的。

      FD_SET(fd_set *fdset);用于在文件描述符集合中增加一个新的文件描述符。

      FD_CLR(fd_set *fdset);用于在文件描述符集合中删除一个文件描述符。

      FD_ISSET(int fd,fd_set *fdset);用于测试指定的文件描述符是否在该集合中。

      struct timeval结构:

      struct timeval{

      long tv_sec;//second

      long tv_usec;//minisecond

      }

      timeout设置情况:

      null:select将一直被阻塞,直到某个文件描述符上发生了事件。

      0:仅检测描述符集合的状态,然后立即返回,并不等待外部事件的发生。

      特定的时间值:如果在指定的时间段里没有事件发生,select将超时返回。

      --

      ('fd_set') 是一组文件描述符(fd)的集合。由于fd_set类型的长度在不同平台上不同,因此应该用一组标准的宏定义来处理此类变量:

      fd_set set; FD_ZERO(&set); /* 将set清零 */ FD_SET(fd, &set); /* 将fd加入set */ FD_CLR(fd, &set); /* 将fd从set中清除 */ FD_ISSET(fd, &set); /* 如果fd在set中则真 */

      在 过去,一个fd_set通常只能包含少于等于32个文件描述符,因为fd_set其实只用了一个int的比特矢量来实现,在大多数情况下,检查 fd_set能包括任意值的文件描述符是系统的责任,但确定你的fd_set到底能放多少有时你应该检查/修改宏FD_SETSIZE的值。*这个值是系 统相关的*,同时检查你的系统中的select() 的man手册。有一些系统对多于1024个文件描述符的支持有问题。

      多路复用的方式是真正实用的服务器程序,非多路复用的网络程序只能作为学习或着陪测的角色。本文说下个人

      接触过的多路复用函数:select/poll/epoll/port。kqueue的*nix系统没接触过,估计熟悉了上面

      四种,kqueue也只是需要熟悉一下而已。

      一、select模型

      select原型: int select(int n ,fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

      其中参数n表示监控的所有fd中最大值+1。

      和select模型紧密结合的四个宏,含义不解释了:

      FD_CLR(int fd, fd_set *set);

      FD_ISSET(int fd, fd_set *set);

      FD_SET(int fd, fd_set *set);

      FD_ZERO(fd_set *set);

      理解select模型的关键在于理解fd_set,为说明方便,取fd_set长度为1字节,fd_set中的每一bit可以对应一个文件描述符fd。则1字节长的fd_set最大可以对应8个fd。

      (1)执行fd_set set; FD_ZERO(&set);则set用位表示是0000,0000。

      (2)若fd=5,执行FD_SET(fd,&set);后set变为0001,0000(第5位置为1)

      (3)若再加入fd=2,fd=1,则set变为0001,0011

      (4)执行select(6,&set,0,0,0)阻塞等待

      (5)若fd=1,fd=2上都发生可读事件,则select返回,此时set变为0000,0011。注意:没有事件发生的fd=5被清空。

      基于上面的讨论,可以轻松得出select模型的特点:

      (1)可监控的文件描述符个数取决与sizeof(fd_set)的值。我这边服务 器上sizeof(fd_set)=512,每bit表示一个文件描述符,则我服务器上支持的最大文件描述符是512*8=4096。据说可调,另有说虽 然可调,但调整上限受于编译内核时的变量值。本人对调整fd_set的大小不太感兴趣,参考http://www.cppblog.com /CppExplore/archive/2008/03/21/45061.html中的模型2(1)可以有效突破select可监控的文件描述符上 限。

      (2)将fd加入select监控集的同时,还要再使用一个数据结构array保存放到select监控集中的fd,一是用于再select 返回后,array作为源数据和fd_set进行FD_ISSET判断。二是select返回后会把以前加入的但并无事件发生的fd清空,则每次开始 select前都要重新从array取得fd逐一加入(FD_ZERO最先),扫描array的同时取得fd最大值maxfd,用于select的第一个 参数。

      (3)可见select模型必须在select前循环array(加fd,取maxfd),select返回后循环array(FD_ISSET判断是否有时间发生)。

      下面给一个伪码说明基本select模型的服务器模型:

      array[slect_len];

      nSock=0;

      array[nSock++]=listen_fd;(之前listen port已绑定并listen)

      maxfd=listen_fd;

      while{

      FD_ZERO(&set);

      foreach (fd in array)

      {

      fd大于maxfd,则maxfd=fd

      FD_SET(fd,&set)

      }

      res=select(maxfd+1,&set,0,0,0);

      if(FD_ISSET(listen_fd,&set))

      {

      newfd=accept(listen_fd);

      array[nsock++]=newfd;

      if(--res<=0) continue

      }

      foreach 下标1开始 (fd in array)

      {

      if(FD_ISSET(fd,&tyle="COLOR: #ff0000">set))

      执行读等相关操作

      如果错误或者关闭,则要删除该fd,将array中相应位置和最后一个元素互换就好,nsock减一

      if(--res<=0) continue

      }

      }

     

     

     

      服务器端代码:

      引用

      #include <sys/types.h>

      #include <sys/socket.h>

      #include <stdio.h>

      #include <netinet/in.h>

      #include <sys/time.h>

      #include <sys/ioctl.h>

      #include <unistd.h>

      #include <stdlib.h>

      int main()

      {

      int server_sockfd, client_sockfd;

      int server_len, client_len;

      struct sockaddr_in server_address;

      struct sockaddr_in client_address;

      int result;

      fd_set readfds, testfds;

      /*创建套接字:IPv4, tcp流套接字*/

      server_sockfd = socket(AF_INET, SOCK_STREAM, 0);

      server_address.sin_family = AF_INET;

      /*INADDR_ANY代表本机IP,htonl将其转换为网络字节顺序(大端模式)*/

      server_address.sin_addr.s_addr = htonl(INADDR_ANY);

      server_address.sin_port = htons(9734);

      server_len = sizeof(server_address);

      /*将端口与套接字绑定*/

      bind(server_sockfd, (struct sockaddr *)&server_address, server_len);

      /*监听,可接受5个连接请求*/

      listen(server_sockfd, 5);

      FD_ZERO(&readfds);

      FD_SET(server_sockfd, &readfds);

      /*等待客户端请求*/

      while(1) {

      char ch;

      int  fd;

      int  nread;

      testfds = readfds;

      /*服务器在select后等待客户端的请求(服务器阻塞)*/

      printf("server waiting/n");

      result = select(FD_SETSIZE, &testfds, (fd_set *)0,

      (fd_set *)0, (struct timeval *)0);

      if (result < 1) {

      perror("server");

      exit(1);

      }

      /*轮询,实际程序不使用这种极度耗时的方法*/

      for (fd = 0; fd < FD_SETSIZE; fd++) {

      if (FD_ISSET(fd, &testfds)) {

      if (fd == server_sockfd) {

      client_len = sizeof(client_address);

      client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address,

      &client_len);                    /*接收客户端连接请求,并返回连接套接字用于收发数据*/

      FD_SET(client_sockfd, &readfds);    /*需要监视发来请求的客户端*/

      printf("adding client on fd %d/n", client_sockfd);

      } else {                                                           /*客户端发生“状况”*/

      ioctl(fd, FIONREAD, &nread);

      if (nread == 0) {

      close(fd);                                        /*读取不到任何内容,关闭与客户端的连接套接字*/

      FD_CLR(fd, &readfds);              /*清除客户端套接字描述符,不再对其"关注"*/

      printf("removing client on fd %d/n", fd);

      } else {

      read(fd, &ch, 1);

      sleep(5);

      printf("serving client on fd %d/n", fd);

      ch++;

      write(fd, &ch, 1);

      }

      }

      }

      }

      }

      }

     

     

     

      例子2

      #include <stdio.h>

      #include <stdlib.h>

      #include <unistd.h>

      #include <errno.h>

      #include <string.h>

      #include <sys/types.h>

      #include <sys/socket.h>

      #include <netinet/in.h>

      #include <arpa/inet.h>

      #define MYPORT 1234    // the port users will be connecting to

      #define BACKLOG 5     // how many pending connections queue will hold

      #define BUF_SIZE 200

      int fd_A[BACKLOG];    // accepted connection fd

      int conn_amount;    // current connection amount

      void showclient()

      {

      int i;

      printf("client amount: %d/n", conn_amount);

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

      {

      printf("[%d]:%d  ", i, fd_A[i]);

      }

      printf("/n/n");

      }

      int main(void)

      {

      int sock_fd, new_fd;  // listen on sock_fd, new connection on new_fd

      struct sockaddr_in server_addr;    // server address information

      struct sockaddr_in client_addr; // connector's address information

      socklen_t sin_size;

      int yes = 1;

      char buf[BUF_SIZE];

      int ret;

      int i;

      if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)

      {

      perror("socket");

      exit(1);

      }

      if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)

      {

      perror("setsockopt");

      exit(1);

      }

      server_addr.sin_family = AF_INET;         // host byte order

      server_addr.sin_port = htons(MYPORT);     // short, network byte order

      server_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP

      memset(server_addr.sin_zero, '/0', sizeof(server_addr.sin_zero));

      if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)

      {

      perror("bind");

      exit(1);

      }

      if (listen(sock_fd, BACKLOG) == -1)

      {

      perror("listen");

      exit(1);

      }

      printf("listen port %d/n", MYPORT);

      fd_set fdsr;

      int maxsock;

      struct timeval tv;

      conn_amount = 0;

      sin_size = sizeof(client_addr);

      maxsock = sock_fd;

      while (1)

      {

      // initialize file descriptor set

      FD_ZERO(&fdsr);

      FD_SET(sock_fd, &fdsr);

      // timeout setting

      tv.tv_sec = 30;

      tv.tv_usec = 0;

      // add active connection to fd set

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

      {

      if (fd_A[i] != 0)

      {

      FD_SET(fd_A[i], &fdsr);

      }

      }

     

     

     

      ret = select(maxsock + 1, &fdsr, NULL, NULL, &tv);

      if (ret < 0)

      {

      perror("select");

      break;

      } else if (ret == 0)

      {

      printf("timeout/n");

      continue;

      }

      // check every fd in the set

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

      {

      if (FD_ISSET(fd_A[i], &fdsr))

      {

      ret = recv(fd_A[i], buf, sizeof(buf), 0);

      if (ret <= 0)

      {        // client close

      printf("client[%d] close/n", i);

      close(fd_A[i]);

      FD_CLR(fd_A[i], &fdsr);

      fd_A[i] = 0;

      }

      else

      {        // receive data

      if (ret < BUF_SIZE)

      memset(&buf[ret], '/0', 1);

      printf("client[%d] send:%s/n", i, buf);

      }

      }

      }

      // check whether a new connection comes

      if (FD_ISSET(sock_fd, &fdsr))

      {

      new_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &sin_size);

      if (new_fd <= 0)

      {

      perror("accept");

      continue;

      }

      // add to fd queue

      if (conn_amount < BACKLOG)

      {

      fd_A[conn_amount++] = new_fd;

      printf("new connection client[%d] %s:%d/n", conn_amount,

      inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

      if (new_fd > maxsock)

      maxsock = new_fd;

      }

      else

      {

      printf("max connections arrive, exit/n");

      send(new_fd, "bye", 4, 0);

      close(new_fd);

      break;

      }

      }

      showclient();

      }

      // close other connections

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

      {

      if (fd_A[i] != 0)

      {

      close(fd_A[i]);

      }

      }

      exit(0);

      }

  • 相关阅读:
    hi.baidu.com 百度流量统计
    Autofac is designed to track and dispose of resources for you.
    IIS Manager could not load type for module provider 'SharedConfig' that is declared in administration.config
    How to create and manage configuration backups in Internet Information Services 7.0
    定制swagger的UI
    NSwag在asp.net web api中的使用,基于Global.asax
    NSwag Tutorial: Integrate the NSwag toolchain into your ASP.NET Web API project
    JS变量对象详解
    JS执行上下文(执行环境)详细图解
    JS内存空间详细图解
  • 原文地址:https://www.cnblogs.com/hzhida/p/2637171.html
Copyright © 2011-2022 走看看