LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 4672|回复: 2

实时SIGIO队列与sigwaitinfo的结合使用(提高socket服务能力)

[复制链接]
发表于 2007-8-17 21:42:31 | 显示全部楼层 |阅读模式
这个是接收端也就是服务端的代码。
  1. #define _GNU_SOURCE
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <fcntl.h>
  6. #include <errno.h>
  7. #include <string.h>
  8. #include <signal.h>
  9. #include <netinet/in.h>
  10. #include <arpa/inet.h>
  11. #include <sys/socket.h>
  12. #include <sys/types.h>
  13. #include <sys/ioctl.h>
  14. #define MAX_LENTH 1500
  15. #define SIG_FIFO_IO SIGRTMIN+1
  16. //这时SIGIO表示实时信号队列已满
  17. static char recv_buf[MAX_LENTH] = {0};
  18. int main(int argc, char *argv[])
  19. {
  20.         int sockfd, on = 1;
  21.         struct sigaction action;
  22.         sigset_t newmask, oldmask;
  23.         struct sockaddr_in addr;
  24.         memset(&addr, 0, sizeof(addr));
  25.         addr.sin_family =  AF_INET;
  26.         addr.sin_addr.s_addr = INADDR_ANY;
  27.         addr.sin_port = htons(50001);
  28.         if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
  29.                 perror("Create socket failed");
  30.                 exit(-1);
  31.         }
  32.         if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
  33.                 perror("Bind socket failed");
  34.                 exit(-1);
  35.         }
  36. /*         memset(&action, 0, sizeof(action));
  37.         action.sa_handler = sigio_handler;
  38.         action.sa_flags = 0;
  39.         sigaction(SIGIO, &action, NULL); */
  40.        
  41.         if (fcntl(sockfd, F_SETOWN, getpid()) == -1) {
  42.                 perror("Fcntl F_SETOWN failed");
  43.                 exit(-1);               
  44.         }
  45.         if (fcntl(sockfd, F_SETSIG, SIG_FIFO_IO) == -1) {
  46.                 perror("Fcntl F_SETSIG failed");
  47.                 exit(-1);               
  48.         }       
  49.         if (ioctl(sockfd, FIOASYNC, &on) == -1) {
  50.                 perror("Ioctl FIOASYNC failed");
  51.                 exit(-1);               
  52.         }
  53.         
  54.         int rcvd_sig, len;
  55.         siginfo_t info;
  56.         sigemptyset(&newmask);
  57.         sigaddset(&newmask, SIG_FIFO_IO);
  58.         sigprocmask(SIG_BLOCK, &newmask, &oldmask);
  59.         while (1) {
  60.                 rcvd_sig = sigwaitinfo(&newmask, &info);//siginfo中的_sigpool{si_band, si_fd},其中si_fd为socket的文件描述符值
  61.                
  62.                 if (rcvd_sig == -1) {
  63.                    perror("sigio: sigwaitinfo");
  64.                    exit(-1);
  65.                 }
  66.                 else {
  67.                         printf("Signal %d, socket fd %d  received from socket\n",
  68.                                  rcvd_sig, info.si_fd);
  69.                         len = recv(sockfd, recv_buf, MAX_LENTH, MSG_DONTWAIT);
  70.                         if( len>0)
  71.                                 puts( recv_buf);
  72.                         exit(-1);
  73.                 }
  74.         }
  75. }
复制代码
效率应该比较高,通过siginfo_t的si_fd可以找到相应的socket文件描述符,所以对多个客户端的连接也能处理,如果还配以使用si_band还能知道该信号具体的含义如下:
POLL_IN     Data input available.  
POLL_OUT     Output buffers available.  
POLL_MSG     Input message available.  
POLL_ERR     I/O error.   
POLL_PRI     High priority input available.  
POLL_HUP     Device disconnected.
这些东西很像poll系统调用中struct pollfd中的revents。   

发送端的代码跟我以前写的这个系列的一样,抄在下方。
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <fcntl.h>
  5. #include <errno.h>
  6. #include <netinet/in.h>                 /*socket address struct*/
  7. #include <arpa/inet.h>                        /*host to network convertion*/
  8. #include <sys/socket.h>
  9. #include <signal.h>
  10. #define MAX_TRANSPORT_LENTH 512
  11. int main()
  12. {
  13.         struct sockaddr_in addr;
  14.         memset(&addr,0,sizeof(addr));
  15.         addr.sin_family =  AF_INET;
  16.         addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  17.         addr.sin_port = htons(50001);
  18.        
  19.         int sock;
  20.         sock = socket(AF_INET,SOCK_DGRAM,0);
  21.         if(sock == -1)
  22.         {
  23.                 perror("Create socket failed");
  24.                 exit(-1);
  25.         }
  26.        
  27.         int ret;
  28.         ret = connect(sock,(struct sockaddr *)&addr,sizeof(addr));
  29.         if(ret == -1)
  30.         {
  31.                 perror("Connect socket failed");
  32.                 exit(-1);               
  33.         }               
  34.         while(1)
  35.         {
  36.                 printf("Will send messge to server\n");
  37.                 write(sock,"Some unknown infomation\n",MAX_TRANSPORT_LENTH);
  38.                 sleep(1);
  39.         }
  40.        
  41. }
复制代码

以上代码版权属于realtang,您可以在GPLv3授权下使用。
发表于 2007-10-17 09:23:49 | 显示全部楼层
请教老大:sigaction(SIGIO, &action, NULL);  中的信号有没有自定义的说法?
windows下不是可以自定义消息,linux支持这种做法吗?我一直困惑这个问题。

如果不能自定义,那怎么知道发出的信号是哪个信号?谢谢!
回复 支持 反对

使用道具 举报

发表于 2007-10-17 09:32:20 | 显示全部楼层
还问老大:
怎么不直接把对客户端的处理直接放才信号处理好处里边?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表