• php socket 模型及效率问题


    // 创建套接字
    socket_create();
    // 绑定
    socket_bind();
    // 监听
    socket_listen();
    
    // 主体, 死循环
    while(true){
      // select模型, 取出可读套接字列表
      socket_select();
    
      foreach(sockets) {
        // 如果是监听连接请求端口的套接字
        if(is listensocket) {
          // 接受请求
          socket_accept();
        }
        else {
          // 读取封包
          socket­_recv();
          // 处理用户动作 {问题就在这}
          process();
        }
      }
    }
    php socket 模型及效率问题
    呼呼安
    3 票
     呼呼安 70
    // 创建套接字
    socket_create();
    // 绑定
    socket_bind();
    // 监听
    socket_listen();
    
    // 主体, 死循环
    while(true){
      // select模型, 取出可读套接字列表
      socket_select();
    
      foreach(sockets) {
        // 如果是监听连接请求端口的套接字
        if(is listensocket) {
          // 接受请求
          socket_accept();
        }
        else {
          // 读取封包
          socket­_recv();
          // 处理用户动作 {问题就在这}
          process();
        }
      }
    }
    
    关于php做服务端的效率, 我想这里是个问题吧。
    在每处理一个用户的动作的时候, 整个循环被阻塞在这里, 导致其他的连接不能接受, 其他用户的动作请求不能被处理。 直到process()函数返回才能处理下一个动作。
    处理一个用户动作的时候, 可能还要涉及到数据库访问等, 可能比较耗时。
    不知道有没有哪位大仙有解决办法呢。
    
    我想的是, 如果能做一个动作队列, 这里的循环只负责接收数据, 然后把数据包保存在一个队列里, 就去接收下一个用户的封包。
    另一个线程(不知道PHP怎么实现线程, 或是能不能实现)从队列中抽取每一个用户的动作请求来处理它。。
    
    或着process()函数能不能做成非阻塞的, 让它可以立即返回。。
    
    小弟初学,如有可笑之处,请见谅!
    
    评论 (0) • 分享 • 链接 • 2012-07-24 
    4个答案 票 数  
    冯义军
    1 票
    冯义军14.02K
    最佳答案
    这个问题我也遇到过到,比如打开两个终端,telnet socket服务端,如果其中一个不返回,另一个终端总是等待。最后使用fork子进程方式解决,大概代码如下,你可以参考下:
    
    死循环部分
    
    do {
                $msgsock = socket_accept($socket);
                $pid = pcntl_fork();
                if($pid == -1) {
                    // fork error ;
                }else if($pid) {
                    socket_close($msgsock);
                }else {
                    $buf = socket_read($msgsock,1024,PHP_NORMAL_READ);
                    $ret = func($buf); //调用函数处理接收到的内容
                    socket_write($msgsock,$ret,strlen($ret));
                    socket_close($msgsock);
                    //posix_kill(posix_getpid(),0);
                    exit();
                }
            }while(true)
    
    评论 (10) • 链接 • 2012-07-25
    0
    @冯义军 你好, 我在本地测试的时候, 可以用cmd运行php, 或是在网页上访问一下, 然后关闭网页就行了, php会一直执行, 然后端口就可以一直访问。。
    但是我放服务器上(linux), 怎么让它一直执行啊, 我用网页访问它的时候可以连接, 如果关了网页, 就会关闭。 – 呼呼安 2012-07-28
    0
    @呼呼安 在 socket服务端程序中 开头增加 ignore_user_abort(1); set_time_limit(0); 这两句,就可以运行一次关浏览器了。
    另外还可以在命令行运行,如 /usr/local/php/bin xxx.php & – 冯义军 2012-07-28
    0
    @冯义军 set_time_limit(0)这个我加了, ignore_user_abort(1);这个没加就不行吗 – 呼呼安 2012-07-30
    0
    @呼呼安 ignore_user_abort();主要是设置与客户机断开是否会终止脚本的行,set_time_limit() 主要是指定程序运行的最大时间。 – 冯义军 2012-08-02
    显示更多隐藏的评论
    呼呼安
    2 票
    呼呼安70
    我貌似自己想到了一个办法。。
    
    process()的地方修改一下, 直接写到数据库里(或着谁有更快的方法请告知)。
    就是我所说的“动作队列”。
    
    再写一个类似的php文件, 也是死循环。 
    while(true) {
    // 从数据库里取出一条待处理动作
    // 处理它
    // 从数据库里删除该动作
    }
    
    甚至可以多运行几次这个文件, 就是不知道想停的时候怎么停 >_<
    
    评论 (0) • 链接 • 2012-07-25
    龙虾猫
    0 票
    龙虾猫1
    风大做了一个基于pcntl的多进程Socket服务框架,可以参考使用下
    http://code.google.com/p/mpass/
  • 相关阅读:
    RWCString 定义 memeroy leak
    打开eclipse报错
    Eclipse 增加php插件
    Shell 字符串的截取
    【转载】Shell判断字符串包含关系的几种方法
    Shell $? $* $@ 等含义
    Shell 获取指定行的内容
    概念性进程
    网络编程
    模块详解
  • 原文地址:https://www.cnblogs.com/archoncap/p/5239742.html
Copyright © 2020-2023  润新知