免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 5888 | 回复: 22
打印 上一主题 下一主题

非阻塞socket转为阻塞后的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-01-31 15:54 |只看该作者 |倒序浏览
socket连接成功后,由非阻塞转为阻塞之后,select得到可读,可是读的时候没有读到数据,这是什么原因呢?
代码如下:

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/socket.h>
  4. #include <sys/select.h>
  5. #include <netinet/in.h>
  6. #include <arpa/inet.h>
  7. #include <netdb.h>
  8. #include <errno.h>
  9. #include <string.h>
  10. #include <strings.h>
  11. #include <unistd.h>
  12. #include <fcntl.h>

  13. #define STATUS_OOS                                0
  14. #define STATUS_CONNECTING                1
  15. #define STATUS_INSERVICE                2
  16. int main()
  17. {
  18.         int status = STATUS_OOS;
  19.         int sockfd = 0;
  20.         int port = 8011;
  21.         char host[] = "192.168.100.209";
  22.        
  23.         struct sockaddr_in serv_addr;
  24.         struct hostent     *hp;
  25.         int           setFlag;
  26.         struct linger linger;
  27.        
  28.         int flags;

  29.         if ( (hp = gethostbyname(host)) == NULL) {
  30.                 //perror ("sockTcpConnect:gethostbyname error ");
  31.                 printf("gethostbyname error host = '%s'\n",host);
  32.                 return 0;
  33.         }
  34.         bcopy(hp->h_addr, (char *) &serv_addr.sin_addr, hp->h_length);

  35.         if ( (sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0 ) {
  36.                 perror ("generate socket error ");
  37.                 return 0;
  38.         }

  39.         bzero((char *)&serv_addr, sizeof(serv_addr));
  40.         serv_addr.sin_family      = AF_INET;
  41.         memcpy (&serv_addr.sin_addr, hp->h_addr, hp->h_length);
  42.         serv_addr.sin_port        = htons(port);

  43.         setFlag = 1;
  44.         if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &setFlag, sizeof(setFlag)) < 0) {
  45.                 close(sockfd);
  46.                 return 0;
  47.         }

  48.         linger.l_onoff = 1;
  49.         linger.l_linger = 0;
  50.           if (setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (char *) &linger, sizeof(linger)) < 0) {
  51.                 close(sockfd);
  52.                 return 0;
  53.         }
  54. /***************************************************/  
  55. //在connect之前,设成非阻塞模式
  56.         flags = fcntl(sockfd, F_GETFL,0);
  57.         fcntl(sockfd,F_SETFL, flags | O_NONBLOCK);
  58. /***************************************************/  

  59.         if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
  60.                 if(errno != EINPROGRESS){
  61.                         close(sockfd);
  62.                         return 0;
  63.                 }
  64.                 status = STATUS_CONNECTING;
  65.         }
  66.         else {
  67.                 status = STATUS_INSERVICE;
  68.         }
  69.         while(1) {
  70.                 fd_set          fdread;
  71.                 fd_set          fdwrite;
  72.                 struct timeval  tvSelect;
  73.                 int  n;
  74.            
  75.                 FD_ZERO(&fdread);
  76.                 FD_ZERO(&fdwrite);
  77.                 FD_SET(sockfd, &fdread);
  78.                 tvSelect.tv_sec         = 0;
  79.                 tvSelect.tv_usec         = 500;
  80.                 if(STATUS_CONNECTING==status){
  81.                         fdwrite = fdread;
  82.                 }
  83.            
  84.                 int retval = select(sockfd + 1, &fdread, status==STATUS_CONNECTING?&fdwrite:NULL, NULL, &tvSelect);
  85.                 if(retval < 0){
  86.                         if ( errno == EINTR ){
  87.                                 printf("select error\n");
  88.                                 continue;
  89.                         }
  90.                         else{
  91.                                 printf("error\n");
  92.                                 close(sockfd);
  93.                                 return 0;
  94.                         }
  95.                 }
  96.                 else if(retval == 0){
  97.                         if(status == STATUS_CONNECTING){
  98.                                 printf("select timeout, state CONNECTING, still connecting...\n");
  99.                                 continue;
  100.                         }
  101.                 }
  102.                 else if((STATUS_CONNECTING==status) && ( FD_ISSET(sockfd, &fdread) || FD_ISSET(sockfd, &fdwrite) ) ){
  103.                         printf("no-block connnect select return, check socket.\n");
  104.                         int error;
  105.                         socklen_t len = sizeof(error);
  106.                         if(getsockopt(sockfd,SOL_SOCKET,SO_ERROR,&error,&len) < 0 || error != 0){
  107.                                 printf("getsockopt return error, %d:%d\n", error, errno);
  108.                                 close(sockfd);
  109.                                 return 0;       
  110.                         }
  111.                         else{
  112.                                 printf("no-block connnect ok, set socket to block mode.\n");
  113. /***************************************************/  
  114. //在connect成功之后,设成阻塞模式
  115.                                 int flags = fcntl(sockfd, F_GETFL,0);
  116.                                 flags &= ~O_NONBLOCK;
  117.                                 fcntl(sockfd,F_SETFL, flags);
  118. /***************************************************/  
  119.                                 status = STATUS_INSERVICE;
  120.                                 continue;
  121.                         }
  122.                 }
  123.                 else if((STATUS_INSERVICE==status)&& FD_ISSET(sockfd, &fdread)) {
  124.                         char recvbuf[10240];
  125.                         bzero(recvbuf, sizeof(recvbuf));
  126.                     n = read (sockfd, recvbuf, sizeof(recvbuf) - 1);
  127.                     printf("read data length is %d\n", n);
  128. //select返回可读,应该是不会读不到数据的,但收了几个消息之后,就会返回读取长度为0,不知道原因
  129.                         if(n == 0){
  130.                                 close(sockfd);
  131.                                 return 0;
  132.                         }
  133.                         else if (n < 0) {
  134.                                 printf("read return<0, errno is %d\n", errno);
  135.                               if ( errno == EINTR ) {
  136.                                       continue;
  137.                               }
  138.                                 else {
  139.                                         close(sockfd);
  140.                                         return 0;
  141.                                 }
  142.                         }
  143.                         //proc data......
  144.                 }
  145.         }
  146.         close(sockfd);
  147.         return 1;
  148. }

复制代码

[ 本帖最后由 vafls_scott 于 2007-1-31 16:33 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2007-01-31 16:33 |只看该作者
急啊,顶一下

论坛徽章:
0
3 [报告]
发表于 2007-01-31 16:54 |只看该作者
你再次SELECT 看看。

论坛徽章:
0
4 [报告]
发表于 2007-01-31 17:10 |只看该作者
还是能select到,但read的时候还是0。真奇怪

论坛徽章:
0
5 [报告]
发表于 2007-01-31 19:18 |只看该作者
man 7 socket

套接字对端关闭时select认为是可读。

别用select了,多恶心的函数啊!!

论坛徽章:
0
6 [报告]
发表于 2007-01-31 19:21 |只看该作者
原帖由 JohnBull 于 2007-1-31 19:18 发表
man 7 socket

套接字对端关闭时select认为是可读。

别用select了,多恶心的函数啊!!


请教一下,这个时候应该用什么函数呢?

--

论坛徽章:
0
7 [报告]
发表于 2007-01-31 19:28 |只看该作者
原帖由 langue 于 2007-1-31 19:21 发表


请教一下,这个时候应该用什么函数呢?

--


poll啊,poll能区分数据到达和连接状态改变(POLLHUP和POLLIN)

论坛徽章:
39
2017金鸡报晓
日期:2017-02-08 10:39:4219周年集字徽章-周
日期:2023-04-15 12:02:2715-16赛季CBA联赛之深圳
日期:2023-02-16 14:39:0220周年集字徽章-年
日期:2022-08-31 14:25:28黑曼巴
日期:2022-08-17 18:57:0919周年集字徽章-年
日期:2022-04-25 13:02:5920周年集字徽章-20	
日期:2022-03-29 11:10:4620周年集字徽章-年
日期:2022-03-14 22:35:1820周年集字徽章-周	
日期:2022-03-09 12:51:3220周年集字徽章-年
日期:2022-02-10 13:13:4420周年集字徽章-周	
日期:2022-02-03 12:09:4420周年集字徽章-20	
日期:2022-01-25 20:14:27
8 [报告]
发表于 2007-01-31 19:30 |只看该作者
select 恶心?没听说过!用epoll移植到windows下试试!

论坛徽章:
0
9 [报告]
发表于 2007-01-31 19:32 |只看该作者
原帖由 JohnBull 于 2007-1-31 19:28 发表


poll啊,poll能区分数据到达和连接状态改变(POLLHUP和POLLIN)


原来是这样。谢谢。但我觉得 select() 还行,个人意见

--

论坛徽章:
0
10 [报告]
发表于 2007-01-31 19:44 |只看该作者
原帖由 醉卧水云间 于 2007-1-31 19:30 发表
select 恶心?没听说过!用epoll移植到windows下试试!


且不说select把描述符集简单武断地分成了“read/write/exception”而限制了其表达能力、每次监测之前都要重写描述符集,单就select的第一个参数就够滑稽的了--请求监视描述符最大值+1 :wink::wink:

在有poll可以用的场合,我决不用select!

评分

参与人数 1可用积分 +3 收起 理由
langue + 3 有个性。

查看全部评分

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

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP