五月综合缴情婷婷六月,色94色欧美sute亚洲线路二,日韩制服国产精品一区,色噜噜一区二区三区,香港三级午夜理伦三级三

您現(xiàn)在的位置: 365建站網(wǎng) > 365文章 > 用 Socket 和 Pcntl 實現(xiàn)一個多線程服務(wù)器(一)

用 Socket 和 Pcntl 實現(xiàn)一個多線程服務(wù)器(一)

文章來源:365jz.com     點擊數(shù):1885    更新時間:2009-09-28 09:24   參與評論
    要建立一個簡單的服務(wù),如果不考慮性能方面的問題,比如并發(fā)100 左右的服務(wù),可以簡單的用 Socket + Pcntl。
 來實現(xiàn),我準備寫一個系列的教程,讓新手就能進行編寫socket 服務(wù)。
    下面要實現(xiàn)的是這樣一個服務(wù),就是能進行加減乘除的四則運算。數(shù)字可以是任意大的數(shù)??梢杂孟旅娴拿顪y試這個服務(wù):
telnet 122.224.124.251 8086
就會進入下面的界面:


 Welcome to the PHP Test Server.

 To quit, type 'quit'.
#


輸入quit 就可以退出。
下面演示功能:
輸入: 11111111111111111111111 * 222222222222222222222222222

# 11111111111111111111111 * 222222222222222222222222222
# result is : 2469135802469135802469111108641975308641975308642.
就能把結(jié)果計算出來。

這個演示的服務(wù),可以多個人同時進行 運算。這個或許就是一個基本的多線程服務(wù),比如,web服務(wù)器
就是一個多線程服務(wù),但是,它要處理大量線程,進程的并發(fā)問題。所以比較復(fù)雜。
下面是代碼, 具體的解釋就在后面的教程中了。

這個類是處理的是進程控制,具體的邏輯處理封裝在了 clientHandle 這個回調(diào)函數(shù)里面。通過修改這個回調(diào)
函數(shù)的內(nèi)容,你也能很快的定制一個自己的服務(wù)器。
<?php
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");
?>
Tag標簽: php,PCNTL,Socket

如對本文有疑問,請?zhí)峤坏浇涣髡搲瑥V大熱心網(wǎng)友會為你解答?。?點擊進入論壇

發(fā)表評論 (1885人查看,0條評論)
請自覺遵守互聯(lián)網(wǎng)相關(guān)的政策法規(guī),嚴禁發(fā)布色情、暴力、反動的言論。
昵稱:
最新評論
------分隔線----------------------------

其它欄目

· 建站教程
· 365學(xué)習(xí)

業(yè)務(wù)咨詢

· 技術(shù)支持
· 服務(wù)時間:9:00-18:00
365建站網(wǎng)二維碼

Powered by 365建站網(wǎng) RSS地圖 HTML地圖

copyright © 2013-2024 版權(quán)所有 鄂ICP備17013400號