免费注册 查看新帖 |

Chinaunix

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

socket_read() 如何实现超时. [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-12-26 15:43 |只看该作者 |倒序浏览
代码如下

  1. $address = "192.168.10.10";
  2. $port = 8082;


  3. do
  4. {
  5.         if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false)
  6.         {
  7.                 echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\r\n";
  8.         }
  9.         //socket_set_option($sock,SOL_SOCKET, SO_RCVTIMEO, array("sec"=>10, "usec"=>0));        //set read data timeout
  10.         if (socket_bind($sock, $address, $port) === false)
  11.         {
  12.                 echo "socket_bind() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\r\n";
  13.                 socket_close($sock);
  14.                 sleep(10);
  15.                 continue;
  16.         }
  17.        
  18.         if (socket_listen($sock, 1) === false)
  19.         {
  20.                 echo "socket_listen() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\r\n";
  21.                 socket_close($sock);
  22.                 sleep(10);
  23.                 continue;
  24.         }
  25.         echo "Server started, accepting connections...\r\n";

  26.         //$read   = array($sock);
  27.         //$write  = NULL;
  28.         //$except = NULL;
  29.         //$num_changed_sockets = socket_select($read, $write, $except, 5);
  30.        
  31.         do
  32.         {
  33.                 if (($msgsock = socket_accept($sock)) === false)
  34.                 {
  35.                         echo $str=date('Y-m-d H:i:s')."socket_accept() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\r\n";
  36.                         write_log($str,$argv[1]);
  37.                         sleep(5);
  38.                         continue;
  39.                 }
  40.                 $read   = array($msgsock);
  41.                 $write  = NULL;
  42.                 $except = NULL;
  43.                 //socket_set_option($msgsock,SOL_SOCKET, SO_RCVTIMEO, array("sec"=>5, "usec"=>0));        //set read data timeout
  44.                 if (socket_select($read, $write = NULL, $except = NULL,10,0) < 1)
  45.                 {
  46.                         echo "timeout!\r\n";
  47.                         socket_close($msgsock);
  48.                         continue;
  49.                 }
  50.                 @socket_getpeername($msgsock,$remote_host,$remote_port);
  51.                 echo $str=date('Y-m-d H:i:s ')."Hello $remote_host:$remote_port! had connected! \r\n";
  52.                 write_log($str,$argv[1]);
  53.                 /* Send instructions. */
  54.                 $msg = "\nWelcome to the PHP Test Server. \n" ."To quit, type 'quit'. To shut down the server type 'shutdown'.\r\n";
  55.                 socket_write($msgsock, $msg, strlen($msg));
  56.                
  57.                 do
  58.                 {
  59.                         socket_set_option($msgsock,SOL_SOCKET, SO_RCVTIMEO, array("sec"=>5, "usec"=>0));
  60.                         if (false === ($buf = socket_read($msgsock, 2048, PHP_NORMAL_READ)))
  61.                         {
  62.                                 echo $str=date('Y-m-d H:i:s')."socket_read() failed: reason: " . socket_strerror(socket_last_error($msgsock)) . "\r\n";
  63.                                 write_log($str,$argv[1]);
  64.                                 //socket_close($msgsock);
  65.                                 break ;
  66.                         }
  67.                         if (!$buf = trim($buf))
  68.                         {
  69.                                 continue;
  70.                         }
  71.                         if ($buf == 'quit')
  72.                         {
  73.                                 break;
  74.                         }
  75.                         if ($buf == 'shutdown')
  76.                         {
  77.                                 socket_close($msgsock);
  78.                                 break 2;
  79.                         }
  80.                         $talkback = "PHP: You said '$buf'.\n";
  81.                         socket_write($msgsock, $talkback, strlen($talkback));
  82.                         echo "$buf\n";
  83.                 } while (true);
  84.                 socket_close($msgsock);
  85.         } while (true);
  86.        
  87.         socket_close($sock);
  88. } while (true);
复制代码

当客户端没有数据发送时,如何做到下面这一句超时呢?
if (false === ($buf = socket_read($msgsock, 2048, PHP_NORMAL_READ)))

试过用以下两个方法,都不理想:
if (socket_select($read, $write = NULL, $except = NULL,10,0) < 1)
socket_set_option($msgsock,SOL_SOCKET, SO_RCVTIMEO, array("sec"=>5, "usec"=>0));

而当是以下这种方式时,就OK.


  1. $address = "192.168.10.10";
  2. $port = 8082;

  3. while (true)
  4. {
  5.         /* Create a TCP/IP socket. */
  6.         $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  7.         socket_set_option($socket,SOL_SOCKET, SO_RCVTIMEO, array("sec"=>300, "usec"=>0));        //set no data read timeout
  8.        
  9.         if ($socket === false)
  10.         {
  11.                 echo $str=date('Y-m-d H:i:s')." socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\r\n";
  12.                 //write_log($str,$argv[1]);
  13.         }
  14.         else
  15.         {
  16.                 echo $str=date('Y-m-d H:i:s')." socket successfully created.\r\n";
  17.                 //write_log($str,$argv[1]);
  18.         }
  19.        
  20.         echo "Attempting to connect to '$address' on port '$port'...";

  21.         $result = socket_connect($socket, $address, $port);
  22.         if ($result === false)
  23.         {
  24.                 echo $str=date('Y-m-d H:i:s')." socket_connect() failed.\nReason: ($result) " . socket_strerror(socket_last_error($socket)) . "\r\n";
  25.                 write_log($str,$argv[1]);
  26.                 sleep(10);  //set reconnect time
  27.                 continue;
  28.         }
  29.         else
  30.         {
  31.                 echo $str=date('Y-m-d H:i:s')." successfully connected to $address.\r\n";
  32.                 write_log($str,$argv[1]);
  33.         }
  34.        
  35.         //*************************************************** read line write to mysql database **********************
  36.         $i = 0;
  37.         while (true == true)
  38.         {
  39.             $i++;
  40.           //  echo "Sending $i to server.\n";
  41.           //  socket_write($socket, $i, strlen($i));
  42.                 $input = socket_read($socket, 2048);
  43.                 if ($input===false)
  44.                 {
  45.                         break;
  46.                 }
  47.                 else
  48.                 {
  49.                         data_to_mysql($input,$argv[1]);
  50.                 }
  51.            // write_bad($input,$argv[1]);
  52.             echo "Response from server is: $input\n";
  53.         //    if ($i>10) exit();
  54.             //sleep(5);
  55.         }
  56.         //sleep(5);
  57. }       
  58. echo "Closing socket...";
  59. socket_close($socket);

复制代码

[ 本帖最后由 flyingnn 于 2008-12-26 15:48 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2008-12-26 16:03 |只看该作者
当以SERVER方式运行时:
1> 如果使用这一句:
socket_set_option($msgsock,SOL_SOCKET, SO_RCVTIMEO, array("sec"=>5, "usec"=>0));
没有超时的现象出现.
2>.这一句呢:
if (socket_select($read, $write = NULL, $except = NULL,10,0) < 1);
则客户程序连接上以后,如果没有数据发送,则超时,
但是,客户连接上后,发送了数据,后面再没有数据发送了,则没有超时了,不知为何.

当以CLIENT方式运行时,用这一句则可以达到要求,没有数据收到,则超时,就用这一句:
socket_set_option($msgsock,SOL_SOCKET, SO_RCVTIMEO, array("sec"=>5, "usec"=>0));

论坛徽章:
0
3 [报告]
发表于 2008-12-26 18:52 |只看该作者
你应该尝试先搞清楚阻塞IO/与无阻塞IO的概念及含议

论坛徽章:
0
4 [报告]
发表于 2008-12-29 11:50 |只看该作者
用无阻塞IO的话,就是socket_set_nonblock()吧,这样也不太好,socket_read()没等行尾,就返回结果了,这样不好.
现在就是想让socket_read()看到有行尾才返回结果,而且如果在一定的时间内还没有返回,则超时.

论坛徽章:
0
5 [报告]
发表于 2008-12-29 12:20 |只看该作者
原帖由 flyingnn 于 2008-12-29 11:50 发表
用无阻塞IO的话,就是socket_set_nonblock()吧,这样也不太好,socket_read()没等行尾,就返回结果了,这样不好.
现在就是想让socket_read()看到有行尾才返回结果,而且如果在一定的时间内还没有返回,则超时.


那就用 NON-BLOCKING 的 IO, 搭配 socket_select() 实现一个 socket_gets 之类的...

socket_read 可概要不管读到的是不是 \r \n 之类,

简单来说就是将 socket 设为无阻塞, 然后调用 socket_select() 并指定一个你所希望的"超时时间", 这样无论 SOCKET 是否可读都会返回.

socket_select() 返回表示有数据可读或者出现了系统的中断调用(如信号)或者超时了,  如果出错 socket_selecT() 返回 false, 如果超时应该是返回 0(int),

如果是有数据可读那么调用 socket_read 一字节一字节的读取并加入字符串中, 直到出现 \r\n , 同时你也要考虑 socket_read() 的时候出现的意外错误.


其实建议你用 fsockopen() 这个PHP包装好并且返回 stream 句柄的函数, 你只要调用 fgets() 和设定一个 stream_set_timeout 就可以了

by the way, PHP 手册上有一个 socket_read 的第三参数, 设为 PHP_NORMAL_READ 会自动卡到 \r\n 这里, 搭配 socket_select 应该就可以简单实现了

[ 本帖最后由 hightman 于 2008-12-29 12:38 编辑 ]

论坛徽章:
0
6 [报告]
发表于 2008-12-29 14:04 |只看该作者
现在就是这样的,用 NON-BLOCKING 的 IO, socket_set_nonblock(),搭配 socket_select(),这样的情况,是客户连上后,如果没有任何输入,就会超时,但是如果客户连接上以后,输入了一些字符,就不会超时了,然后,socket_read(),就算加上了第三个参数socket_read($msgsock, 2048, PHP_NORMAL_READ),在这时,它也不管有没有看到\r\n,也会返回结果的.

[ 本帖最后由 flyingnn 于 2008-12-29 14:05 编辑 ]

论坛徽章:
0
7 [报告]
发表于 2008-12-29 14:16 |只看该作者
现在程序是作为SERVER运行的,客户程序自动连接后发送数据的,fsockopen()可以作为SERVER端运行吗?

论坛徽章:
0
8 [报告]
发表于 2008-12-29 14:21 |只看该作者
现在不行的话,只有这样解决了:
用 socket_set_nonblock(),搭配 socket_select(),用 socket_read 一字节一字节的读取并加入字符串中, 直到出现 \r\n.

很感谢版主的热心帮助.在此谢过了!

论坛徽章:
0
9 [报告]
发表于 2008-12-29 14:25 |只看该作者
另外有个问题就是,为什么只有客户端输入字符后,才会输出这一句呢?
echo $str=date('Y-m-d H:i:s ')."Hello $remote_hostremote_port! had connected! \r\n";
而不是客户一连接上就输出呢?

论坛徽章:
0
10 [报告]
发表于 2008-12-29 19:32 |只看该作者
原帖由 flyingnn 于 2008-12-29 14:04 发表
现在就是这样的,用 NON-BLOCKING 的 IO, socket_set_nonblock(),搭配 socket_select(),这样的情况,是客户连上后,如果没有任何输入,就会超时,但是如果客户连接上以后,输入了一些字符,就不会超时了,然后,socket_r ...


你可以再判断socket_read得到的数据最后一个字节是不是\n
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP