进程相关信息
https://segmentfault.com/a/1190000003503671
(重要)https://www.cnblogs.com/iforever/p/9039579.html
https://segmentfault.com/a/1190000008955481
单用户版本
server.php
$socket=stream_socket_server("tcp://127.0.0.1:8000",$errno,$error); while(true){ $client=stream_socket_accept($socket); $message="AAA-".mt_rand(1,10); fwrite($client,$message,strlen($message)); $readStr=fread($client,2048); printf("\n%s\n",$readStr); //$readStr=fread($client,1024); //printf("read:".$readStr); fclose($client); } fclose($socket);
client.php
$client=stream_socket_client("tcp://127.0.0.1:8000",$errno,$errstr); if(!$client){ printf("errno:%s error:%s",$errno,$error); } $message="hellow".microtime(true); fwrite($client,$message,strlen($message)); $info=fread($client,2048); echo $info."\n"; fclose($client);
第二个版本:
多客户端连接版本
server.php
$socket=stream_socket_server("tcp://127.0.0.1:8000",$errno,$error); while(true){ $client=stream_socket_accept($socket); //$message="AAA-".mt_rand(1,10); //$message=fgets($client); //fwrite($client,$message,strlen($message)); $pid=pcntl_fork(); if($pid==-1){ continue; }elseif($pid==0){ //处理业务逻辑 while(true && $client){ $readStr=fread($client,2048); if(empty($readStr)){ continue; usleep(10); } if(trim($readStr=='exit')) break; printf("\n%s\n",$readStr); fwrite($client,$readStr,strlen($readStr)); } //$readStr=fread($client,1024); //printf("read:".$readStr); $myid=getmypid(); var_dump("myid {$myid}\n"); fclose($client); }else{ pcntl_wait($status,WNOHANG); //pcntl_wait($status,WUNTRACED); } usleep(1); } fclose($socket);
客户端持续连接 wclient.php
$client=stream_socket_client("tcp://127.0.0.1:8000",$errno,$errstr); if(!$client){ printf("errno:%s error:%s",$errno,$error); } while(true && $client){ printf('请输入信息:'); $message=trim(fgets(STDIN)); if($message==='exit') break; fwrite($client,$message,strlen($message)); $info=fread($client,2048); printf("server say:%s".PHP_EOL,$info); } fclose($client); //这以上就是php循环监听,循环发送数据
以上的程序,使用了多进程的方式去同时接收多个客户端发送来的数据。
尚未实现:
客户端退出,还未能监听到。
客户端退出 ,开启的进程没有退出。
我在想,当客户端请求过来的时候,我这里只有一个进程,在处理,就ok了,可以创造多个进程,但是我们必须适用阻塞模式,
这样的情况,客户端不管发送多少来数据,都能进行接收。
且进程处理完了,就 结束了。
第三版:
多客户端连接
vm/bserver.php
#$socket=stream_socket_server("tcp://0.0.0.0:8000",$errno,$error,STREAM_SERVER_BIND | STREAM_SERVER_LISTEN); $socket=stream_socket_server("tcp://0.0.0.0:8000",$errno,$error); stream_set_blocking($socket,0); $connections = []; $read = []; $write = null; $except = null; while (1) { // look for new connections if ($c = @stream_socket_accept($socket, empty($connections) ? -1 : 0, $peer)) { echo $peer.' connected'.PHP_EOL; fwrite($c, 'Hello '.$peer.PHP_EOL); $connections[$peer] = $c; } // wait for any stream data $read = $connections; if (stream_select($read, $write, $except, 5)) { foreach ($read as $c) { $peer = stream_socket_get_name($c, true); if (feof($c)) { echo 'Connection closed '.$peer.PHP_EOL; fclose($c); unset($connections[$peer]); } else { $contents = fread($c, 1024); echo $peer.': '.trim($contents).PHP_EOL; } } } } fclose($socket);
client.php
$client=stream_socket_client("tcp://127.0.0.1:8000",$errno,$errstr); if(!$client){ printf("errno:%s error:%s",$errno,$error); } $message="hellow".microtime(true); sleep(30); fwrite($client,$message,strlen($message)); $info=fread($client,2048); echo $info."\n"; fclose($client);
运行实例:
[root@localhost vm]# php client.php Hello 127.0.0.1:58360 [root@localhost vm]# php bserver.php 127.0.0.1:58360 connected 127.0.0.1:58360: hellow Connection closed 127.0.0.1:58360
第四版
多进程版本
vm/server.php
$socket=stream_socket_server("tcp://127.0.0.1:8000",$errno,$error); while(true){ $client=stream_socket_accept($socket,-1,$peer); if(!$client) continue; $pid=pcntl_fork(); if($pid==-1){ continue; }elseif($pid==0){ //处理业务逻辑 $readStr=fread($client,2048); if(trim($readStr=='exit')|| empty($readStr)){ fclose($client); printf("close client:%s\n",$peer); exit; } printf("\n%s send data: %s\n",$peer,$readStr); fwrite($client,strrev($readStr),strlen($readStr)); //$readStr=fread($client,1024); //printf("read:".$readStr); //$myid=getmypid(); //var_dump("myid {$myid}\n"); fclose($client); printf("\nclose client:%s\n",$peer); exit; }else{ pcntl_wait($status,WNOHANG); //pcntl_wait($status,WUNTRACED); } } fclose($socket);
client.php
$client=stream_socket_client("tcp://127.0.0.1:8000",$errno,$errstr); if(!$client){ printf("errno:%s error:%s",$errno,$error); } $message="hellow".microtime(true); fwrite($client,$message,strlen($message)); $info=fread($client,2048); echo $info."\n"; sleep(60); fclose($client);
一般情况下,使用第三个版本吧,这样的话速度会比较块,
因为系统创建进程也是需要耗费时间的。
第五个版本:
win要用iocp啊, linux要用epoll啊 http://developer.51cto.com/art/201506/479431.htm,google就轻言细语的跟我说,高并发下的select不要用啊,效率低
$sfd = stream_socket_server ('tcp://0.0.0.0:1234', $errno, $errstr); stream_set_blocking($sfd, 0); $base = event_base_new(); $event = event_new(); event_set($event, $sfd, EV_READ | EV_PERSIST, 'ev_accept', $base); event_base_set($event, $base); event_add($event); event_base_loop($base); function ev_accept($socket, $flag, $base) { $connection = stream_socket_accept($socket); stream_set_blocking($connection, 0); $buffer = event_buffer_new($connection, 'ev_read', NULL, 'ev_error', $connection); event_buffer_base_set($buffer, $base); event_buffer_timeout_set($buffer, 30, 30); event_buffer_watermark_set($buffer, EV_READ, 0, 0xffffff); event_buffer_priority_set($buffer, 10); event_buffer_enable($buffer, EV_READ | EV_PERSIST); } function ev_error($buffer, $error, $connection) { event_buffer_disable($buffer, EV_READ | EV_WRITE); event_buffer_free($buffer); fclose($connection); } function ev_read($buffer, $connection) { $read = event_buffer_read($buffer, 256); //do something.... }
socket_select() 这个选择是有个数限制的,1024个
把程序源码上传上来:以备后用
以至于上边还是有部分瑕疵,比如说 使用 fgets 是否可以读取数据?
多客户端实现的原理是什么?为什么使用stream_select
有时间搞明白吧