Socket学习 - PHP+Socket多进程处理请求学习

本文介绍如何使用PHP的Socket编程实现多进程服务端,解决单进程处理多个客户端请求时的问题。通过pcntl_fork函数创建子进程,每个子进程独立处理客户端请求,避免了请求阻塞的情况。

前面我们写的Socket代码其实都是单进程的。这导致如果有一个连接很繁忙,那么后面的连接都要等待。于是多进程这个时候就重要了

0.回顾
Socket学习 - 开启Socket学习之旅
Socket学习 - 从这个角度学http协议就很简单了
Socket学习 - tcp协议速度入门和http协议的区别
Socket学习 - 撕开websocket神秘的外衣
Socket学习 - 撕开远程调用的逼格外衣(上)
Socket学习 - 撕开远程调用的逼格外衣(下)超简易仿制一个RPC客户端

1.单进程

<?php

$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
socket_bind($socket,'127.0.0.1',9090) or die('error');
socket_listen($socket,5);

while(true){
    $client = socket_accept($socket);   // 有人打电话进来
    $buf = socket_read($client,1024);   // 一次读取1024的长度
    echo $buf;

    if(preg_match('/sleep/i',$buf)){
        sleep(10);

        $html = 'HTTP/1.1 200 OK'.PHP_EOL
            .'Content-Type: text/html;charset=utf-8'.PHP_EOL.PHP_EOL;
        socket_write($client,$html);
        socket_write($client,'this is server,休克了10秒,模拟很繁忙的样子');
    }else{
        socket_write($client,'this is server');
    }

    socket_close($client);
}

socket_close($socket);

上面代码,是一个单进程的socket服务端,通过分析客户端发送来的HTTP内容中是否有sleep字符串来判断,是否sleep。
运行这个服务,然后我们测试:
这里写图片描述
http://127.0.0.1:9090/ ,浏览器马上输出:this is server。
这里写图片描述
http://127.0.0.1:9090/?sleep,请求地址中带上了sleep,等待10秒才输出。

如果我们一个客户端先请求http://127.0.0.1:9090/?sleep,另一个客户端接着请求http://127.0.0.1:9090/。那么第二个客户端就会”卡住”,等待前面那个客户端完成。这就是单进程。

2.多进程
PHP多进程编程是需要一个扩展的,下面是安装步骤:

1)、进程PHP源码文件。进入ext/pcntl
2)、执行phpize
3)、执行 ./configure --prefix=/usr/local/php --with-php-config=/usr/local/php/bin/php-config (请根据自己的路径修改,不要无脑抄袭)
4)、make然后make install
5)、打开你的PHP配置文件(php --ini),加入 extension=pcntl.so

这时php -m就会出现相关扩展。

学习php的多进程,看我们的官网文档:http://php.net/manual/zh/book.pcntl.php
先来学习一个函数pcntl_fork,官方也给了我们示例:
http://php.net/manual/zh/function.pcntl-fork.php

$pid = pcntl_fork();
//父进程和子进程都会执行下面代码
if ($pid == -1) {
    //错误处理:创建子进程失败时返回-1.
     die('could not fork');
} else if ($pid) {
     //父进程会得到子进程号,所以这里是父进程执行的逻辑
     pcntl_wait($status); //等待子进程中断,防止子进程成为僵尸进程。
} else {
     //子进程得到的$pid0, 所以这里是子进程执行的逻辑。
}

下面我们就来修改我们socket服务端代码:

<?php

$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
socket_bind($socket,'127.0.0.1',9090) or die('error');
socket_listen($socket,5);

while(true){
    $client = socket_accept($socket);

    //创建紫金城
    $pid = pcntl_fork();
    //父进程和子进程都会执行下面代码
    if ($pid == -1) {
        //错误处理:创建子进程失败时返回-1.
        die('could not fork');
    } else if ($pid) {
        //父进程会得到子进程号,所以这里是父进程执行的逻辑
        //pcntl_wait($status); //等待子进程中断,防止子进程成为僵尸进程。
        socket_close($client);
    } else {
        //子进程得到的$pid为0, 所以这里是子进程执行的逻辑。
        $buf = socket_read($client,1024);
        echo $buf;
        if(preg_match('/sleep/i',$buf)){
            sleep(10);
            $html = 'HTTP/1.1 200 OK'.PHP_EOL
                .'Content-Type: text/html;charset=utf-8'.PHP_EOL.PHP_EOL;
            socket_write($client,$html);
            socket_write($client,'this is server,休克了10秒,模拟很繁忙的样子');
        }else{
            socket_write($client,'this is server');
        }
        socket_close($client);
    }
}

socket_close($socket);

注意,我们这里把所有的socket都放到了子进程中处理。

然后我们一个客户端请求http://127.0.0.1:9090/?sleep ,接着另一个客户端请求http://127.0.0.1:9090/ ,就不会发生“卡住”现象了。因此这时服务端已经不是单进程,而是多进程。

3.其他linux知识点
根据名称查看进程

ps -ef |grep server.php

根据端口查看进程:

netstat -anp |grep 9090
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值