LinuxSir.cn,穿越时空的Linuxsir!

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

select 使用难题

[复制链接]
发表于 2006-2-21 09:10:35 | 显示全部楼层 |阅读模式
一个简单的select学习 但是在服务端或者客户端断开的时候
另一个就会不断打印 上次接受到的内容 本人很菜 怎么也看不出来问题
还请高手指教

  1. server.c
  2. #include    <math.h>
  3. #include    <stdio.h>
  4. #include    <stdlib.h>
  5. #include    <string.h>
  6. #include    <strings.h>
  7. #include    <fcntl.h>
  8. #include    <dirent.h>
  9. #include    <sys/types.h>
  10. #include    <sys/stat.h>
  11. #include    <errno.h>
  12. #include    <sys/msg.h>
  13. #include    <unistd.h>
  14. #include    <time.h>
  15. #include    <sys/socket.h>
  16. #include    <netinet/in.h>
  17. #include    <arpa/inet.h>
  18. #include    <sys/msg.h>
  19. #include    <signal.h>
  20. #include    <sys/uio.h>
  21. #include    <sys/ipc.h>
  22. #include    <netdb.h>
  23. #include    <sys/wait.h>
  24. #include    <sys/time.h>

  25. void SetExitFlag(int signo);

  26. int flag=1;

  27. int main(){
  28.        
  29.         struct sockaddr_in servaddr,cliaddr;
  30.         struct hostent *lhost;
  31.         int sfd;
  32.         int reuseaddr = 1;
  33.         int recvfd;
  34.         int clilen=sizeof(struct sockaddr_in);
  35.         int recvlen;
  36.         char buf[1024];
  37.         int sendlen;
  38.         struct                 sigaction act,oact;
  39.         uint16_t port;
  40.         char addr[17];
  41.         fd_set readset,writeset;
  42.        
  43.         memset(buf,0,sizeof(buf));
  44.         memset(addr,0,sizeof(addr));
  45.        
  46.         /**信号设置**/
  47.         act.sa_handler=SetExitFlag;
  48.         sigemptyset(&act.sa_mask);
  49.         act.sa_flags=0;
  50.         if(sigaction(SIGINT,&act,&oact)!=0)
  51.         {
  52.                 perror("sigaction");
  53.                 exit(1);
  54.         }
  55.         signal(SIGTERM, SetExitFlag);
  56.         signal(SIGKILL, SetExitFlag);
  57.         signal(SIGSTOP, SetExitFlag);
  58.         signal(SIGQUIT, SetExitFlag);
  59.        
  60.         /*lhost=gethostbyaddr("dctest1");
  61.         printf("主机名:[%s][%s]\n",lhost->h_name,lhost->h_addr);*/
  62.        
  63.         sfd = socket(AF_INET, SOCK_STREAM, 0);
  64.         if(sfd<0)
  65.                 perror("socket ");
  66.         if(setsockopt(sfd,SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)) == -1)
  67.                 perror("reuse addr ");
  68.         if(setsockopt(sfd,SOL_SOCKET, SO_REUSEPORT, &reuseaddr, sizeof(reuseaddr)) == -1)
  69.                 perror("reuse port");
  70.                        
  71.         bzero((char *)&servaddr,sizeof(servaddr));
  72.         servaddr.sin_family=AF_INET;
  73.         servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
  74.         servaddr.sin_port=htons(10006);
  75.        
  76.         if(bind(sfd,(struct sockaddr *)&servaddr,sizeof(struct sockaddr_in)) == -1)
  77.                 perror("bind ");
  78.        
  79.         if(listen(sfd,10) == -1)
  80.                 perror("listen ");
  81.        
  82.        
  83.         while(flag)
  84.         {
  85.                
  86.                 if((recvfd=accept(sfd,(struct sockaddr *)&cliaddr,&clilen)) == -1)
  87.                 {       
  88.                         perror("accept ");
  89.                         break;
  90.                 }
  91.                 port=ntohs(cliaddr.sin_port);
  92.                 strcpy(addr,inet_ntoa(cliaddr.sin_addr));
  93.                 printf("接收到连接 端口:[%d]ip[%s]\n",port,addr);
  94.                 /*FD_ZERO(&readset);
  95.                 FD_SET(0,&readset);
  96.                 FD_SET(recvfd,&readset);
  97.                 if(select(recvfd+1,&readset,NULL,NULL,NULL)<0)
  98.                         perror("select ");*/
  99.                 while(flag)
  100.                 {
  101.                         FD_ZERO(&readset);
  102.                         FD_SET(0,&readset);
  103.                         FD_SET(recvfd,&readset);
  104.                         if(select(recvfd+1,&readset,NULL,NULL,NULL)<0)
  105.                                 perror("select ");
  106.                         if(FD_ISSET(0,&readset))
  107.                         {       
  108.                                 gets(buf);
  109.                                 sendlen=write(recvfd,buf,strlen(buf));
  110.                                 if(sendlen < 0 )
  111.                                 {
  112.                                         perror("send ");
  113.                                         close(recvfd);       
  114.                                         break;
  115.                                 }
  116.                         }
  117.                         if(FD_ISSET(recvfd,&readset))
  118.                         {       
  119.                                 recvlen=read(recvfd,buf,1024);
  120.                                 if(recvlen < 0)
  121.                                 {       
  122.                                         perror("recv ");
  123.                                         close(recvfd);       
  124.                                         break;
  125.                                 }       
  126.                                 else
  127.                                         printf("recv:[%s]\n",buf);
  128.                         }       
  129.                                
  130.                 }
  131.                 close(recvfd);
  132.         }
  133. }

  134. void SetExitFlag(int signo)
  135. {
  136.         flag=0;
  137.         printf("接收到退出信号\n");
  138. }

  139. client.c
  140. #include    <math.h>
  141. #include    <stdio.h>
  142. #include    <stdlib.h>
  143. #include    <string.h>
  144. #include    <strings.h>
  145. #include    <fcntl.h>
  146. #include    <dirent.h>
  147. #include    <sys/types.h>
  148. #include    <sys/stat.h>
  149. #include    <errno.h>
  150. #include    <sys/msg.h>
  151. #include    <unistd.h>
  152. #include    <time.h>
  153. #include    <sys/socket.h>
  154. #include    <netinet/in.h>
  155. #include    <arpa/inet.h>
  156. #include    <sys/msg.h>
  157. #include    <signal.h>
  158. #include    <sys/uio.h>
  159. #include    <sys/ipc.h>
  160. #include    <netdb.h>
  161. #include    <sys/wait.h>
  162. #include    <sys/time.h>


  163. void SetExitFlag(int signo);

  164. int flag=1;

  165. int main(){
  166.        
  167.         struct sockaddr_in conaddr;
  168.         int cfd;
  169.         char buf[1024];
  170.         int sendlen;
  171.         int recvlen;
  172.         fd_set readset,writeset;
  173.         struct                 sigaction act,oact;
  174.        
  175.         memset(buf,0,1024);
  176.         /**信号设置**/
  177.         act.sa_handler=SetExitFlag;
  178.         sigemptyset(&act.sa_mask);
  179.         act.sa_flags=0;
  180.         if(sigaction(SIGINT,&act,&oact)!=0)
  181.         {
  182.                 perror("sigaction");
  183.                 exit(1);
  184.         }
  185.         signal(SIGTERM, SetExitFlag);
  186.         signal(SIGKILL, SetExitFlag);
  187.         signal(SIGSTOP, SetExitFlag);
  188.         signal(SIGQUIT, SetExitFlag);
  189.        
  190.         cfd=socket(AF_INET,SOCK_STREAM,0);
  191.         if(cfd == -1)
  192.                 perror("socket ");
  193.        
  194.         bzero((char *)&conaddr,sizeof(conaddr));
  195.        
  196.         conaddr.sin_family=AF_INET;
  197.         conaddr.sin_addr.s_addr=inet_addr("172.16.227.11");
  198.         conaddr.sin_port=htons(10006);
  199.        
  200.         if(connect(cfd,(struct sockaddr *)&conaddr,sizeof(struct sockaddr_in)) == -1)
  201.         {       
  202.                 perror("bind ");
  203.                 close(cfd);
  204.                 exit(1);
  205.         }       
  206.        
  207.         /*FD_ZERO(&readset);
  208.         FD_SET(0,&readset);
  209.         FD_SET(cfd,&readset);
  210.         if(select(cfd+1,&readset,NULL,NULL,NULL)<0)
  211.                 perror("select ");*/
  212.         while(flag)
  213.         {       
  214.                 FD_ZERO(&readset);
  215.                 FD_SET(0,&readset);
  216.                 FD_SET(cfd,&readset);
  217.                 if(select(cfd+1,&readset,NULL,NULL,NULL)<0)
  218.                         perror("select ");
  219.                 memset(buf,0,sizeof(buf));
  220.                 if(FD_ISSET(0,&readset))
  221.                 {       
  222.                         gets(buf);
  223.                         sendlen=write(cfd,buf,sizeof(buf));
  224.                         if(sendlen<0)
  225.                         {
  226.                                 perror("send ");
  227.                                 break;
  228.                         }
  229.                 }
  230.                 if(FD_ISSET(cfd,&readset))
  231.                 {       
  232.                         recvlen=read(cfd,buf,1024);
  233.                         if(recvlen<0)
  234.                         {
  235.                                 perror("recv ");
  236.                                 break;
  237.                         }
  238.                         else       
  239.                                 printf("接受:[%s]\n",buf);
  240.                 }       
  241.         }
  242.                
  243.         close(cfd);               
  244.        
  245. }       

  246. void SetExitFlag(int signo)
  247. {
  248.         flag=0;
  249.         printf("接收到退出信号\n");
  250. }
复制代码
发表于 2006-2-21 12:01:37 | 显示全部楼层
你把recvlen打印出来看看
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-2-21 16:04:43 | 显示全部楼层
什么意思呢
就是对方连接断了 是不是我判断recvlen 错了呢
把recvlen改成<=0的判断就可以了
perror 的输出是 Invalid argument

这个判断就可以了吧 谢谢了
回复 支持 反对

使用道具 举报

发表于 2006-2-22 09:19:41 | 显示全部楼层
select为-1时,程序应该exit了吧,都出错了。当然如果errno为EINTR还是可以继续让它做下去的。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-2-22 17:44:16 | 显示全部楼层
你理解错我的意思了
比如说 客户端断开  这时候 服务端会不断打印东西
这个时候服务端的select不会报错的
呵呵
回复 支持 反对

使用道具 举报

发表于 2006-2-23 09:00:53 | 显示全部楼层
这时你应该判断write的返回值吧,为-1就意味着出错,程序也该exit才是。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-2-23 09:49:02 | 显示全部楼层
情况是这样的
客户端退出
但是服务端并没有向socket写东西
所以取法判断 write的返回值的
只能用read来做判断
回复 支持 反对

使用道具 举报

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

本版积分规则

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