php pcntl socket,PHP多进程编程(二) 用 Socket 和 Pcntl 实现一个多进程服务器

class Simple_Server

{

private $sock;

private $csock;

private $isListen = true;

private $callback;

private $user;

private $uid;

private $gid;

private $userHome;

private $scriptName = "simple-server";

/**

* use $user set the user run the script.

* fock a thread, init the socket, and wait user to request.

*

*/

function __construct($callback, $ip = '127.0.0.1', $port = '8086',$user = 'daemon')

{

error_reporting(E_ALL);

ini_set("display_errors", 0);

set_time_limit(0);

ob_implicit_flush();

declare(ticks = 1);

$this->callback = $callback;

$this->user = $user;

$this->getUserInfo();

$this->changeIdentity();

$this->daemon();

pcntl_signal(SIGTERM, array($this, 'sigHandler'));

pcntl_signal(SIGINT,  array($this, 'sigHandler'));

pcntl_signal(SIGCHLD, array($this, 'sigHandler'));

$this->run($ip, $port);

}

function run($address, $port)

{

if(($this->sock = socket_create(AF_INET, SOCK_STREAM, 0)) === false)

{

$this->error("failed to create socket: ".socket_strerror($this->sock));

}

$sock = $this->sock;

if(($ret = socket_bind($sock, $address, $port)) === false)

{

$this->error("failed to bind socket: ".socket_strerror($ret));

}

if(($ret = socket_listen($sock, 0)) === false)

{

$this->error("failed to listen to socket: ".socket_strerror($ret));

}

socket_set_nonblock($sock);

$this->log("waiting for clients to connect");

while ($this->isListen)

{

$this->csock = @socket_accept($sock);

if ($this->csock === false)

{

usleep(1000); //1ms

} else if ($this->csock > 0) {

$this->client();

} else {

$this->error("error: ".socket_strerror($this->csock));

}

}

}

/**

* Handle a new client connection

*/

function client()

{

$this->log('begin client');

$ssock = $this->sock;

$csock = $this->csock;

$pid = pcntl_fork();

if ($pid == -1)

{

$this->error("fock clinet child error.");

} else if ($pid == 0)  {

$pid = posix_getpid();

$this->log("begin client child ($pid).");

/* child process */

$this->isListen = false;

$this->log("close sock in child");

socket_close($ssock);

$this->log("begin handle user logic.");

$callback = $this->callback;

call_user_func($callback, $csock, $this);

$this->log("end handle user logic.");

$this->log("close client sock in child.");

socket_close($csock);

$this->log("end client");

} else  {

$this->log("close csock in child");

socket_close($csock);

}

}

function __destruct()

{

@socket_close($this->sock);

@socket_close($this->csock);

$pid = posix_getpid();

$this->log("end daemon in __destruct pid($pid).");

}

function getUserInfo()

{

$uid_name = posix_getpwnam($this->user);

$this->uid = $uid_name['uid'];

$this->gid = $uid_name['gid'];

$this->userHome = $uid_name['dir'];

}

function changeIdentity()

{

if(!posix_setuid($this->uid))

{

$this->error("Unable to setuid to " . $this->uid);

}

}

/**

* Signal handler

*/

function sigHandler($sig)

{

switch($sig)

{

case SIGTERM:

case SIGINT:

exit();

break;

case SIGCHLD:

pcntl_waitpid(-1, $status);

break;

}

}

function error($msg)

{

$str = date("Y-m-d H:i:s") . " " . $msg . "\n";

file_put_contents(dirname(__FILE__) . "/error.log", $str, FILE_APPEND);

exit(0);

}

function log($msg)

{

$str = date("Y-m-d H:i:s") . " " . $msg . "\n";

file_put_contents(dirname(__FILE__) . "/message.log", $str, FILE_APPEND);

}

function daemon()

{

$ppid = posix_getpid();

$this->log("begin parent daemon pid ($ppid)");

$pid = pcntl_fork();

if ($pid == -1)

{

/* fork failed */

$this->error("fork failure!");

} else if ($pid) {

/* close the parent */

$this->log("end parent daemon pid($ppid) exit.");

exit();

} else  {

/* child becomes our daemon */

posix_setsid();

chdir($this->userHome);

umask(0);

$pid = posix_getpid();

$this->log("begin child daemon pid($pid).");

}

}

}

function clientHandle($msgsock, $obj)

{

/* Send instructions. */

$br = "\r\n";

$msg = "$br Welcome to the PHP Test Server. $br $br To quit, type 'quit'.$br# ";

$obj->log($msg);

socket_write($msgsock, $msg, strlen($msg));

$nbuf = '';

socket_set_block($msgsock);

bcscale(4);  // defalult 4 eg. 1 + 2.00001 = 3

do {

if (false === ($nbuf = socket_read($msgsock, 2048, PHP_NORMAL_READ))) {

$obj->error("socket_read() failed: reason: " . socket_strerror(socket_last_error($msgsock)));

}

if (!$nbuf = trim($nbuf)) {

continue;

}

if ($nbuf == 'quit') {

break;

}

if ($nbuf == 'shutdown') {

break;

}

if (empty($nbuf)) continue;

preg_match("/([\d.]+)[\s]*([+\-*\/x])[\s]*([\d.]+)/i", $nbuf , $matches);

$op   = @$matches[2];

$left = @$matches[1];

$right = @$matches[3];

$result = NULL;

if ($op == "+") {

$result = bcadd($left, $right);

} else if ($op == "-") {

$result = bcsub($left, $right);

} else if ($op == "x" || $op == "x" || $op == "*") {

$result = bcmul($left, $right);

} else if ($op == "/") {

$result = bcdiv($left, $right);

} else {

$talkback = "# error: expression \"$nbuf\" error.$br# ";

}

if ($result === NULL) {

socket_write($msgsock, $talkback, strlen($talkback));

} else {

$result = rtrim($result, ".0");

$talkback = "# result is : $result.$br# ";

socket_write($msgsock, $talkback, strlen($talkback));

}

$nbuf = '';

} while (true);

}

$server = new Simple_Server("clientHandle", "122.224.124.251");

?>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值