作为程序员一定要保持良好的睡眠,才能好编程

RPC第四课 stream_socket项目演练演示代码

发布时间:2018-11-15

进程相关信息

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个


把程序源码上传上来:以备后用


socket.zip




以至于上边还是有部分瑕疵,比如说 使用 fgets 是否可以读取数据?


多客户端实现的原理是什么?为什么使用stream_select


有时间搞明白吧