Programming under the model of the Socket service in PHP (synchronous and asynchronous)

Source: Internet
Author: User
Tags foreach fread php code socket strlen usleep

It took us a while to build a high-performance socket service that can handle a large number of connections at the same time, but without specific business.

If we enable a single process server, but the inside of a business takes 1 seconds, then in this 1 seconds is blocked, subsequent requests will wait, if the concurrent three requests, then three requests of the execution time will be Chang 1 seconds, 2 seconds, 3 seconds. There are several ways to increase concurrency:

1: Multiple START process, increase the number of concurrent

2: Optimize the business, reduce time consuming is equivalent to reduce blocking time, increase the number of concurrent

3: Asynchronous programming, avoid blocking, increase the number of concurrent

Here we will focus on the third method to access the third party HTTP as an example.

The code is as follows:

<?php
Synchronous read
function get_data_blocking () {
$socket = Stream_socket_client ("tcp://test.raventech.cn:80", $errno, $errstr, 6);
Fwrite ($socket, "get/sleep1.php http/1.0\r\nhost:test.raventech.cn\r\naccept: */*\r\n\r\n");
$str = "";
while (!feof ($socket)) {
$str. = Fgets ($socket, 1024);
}
Fclose ($socket);
return $str;
}

Asynchronous read
function get_data_unblocking () {
$socket = Stream_socket_client ("tcp://test.raventech.cn:80", $errno, $errstr, 6);
Stream_set_blocking ($socket, 0);
Fwrite ($socket, "get/sleep1.php http/1.0\r\nhost:test.raventech.cn\r\naccept: */*\r\n\r\n");
$write = NULL;
$except = NULL;
while ($socket) {
$read = Array ($socket);
$num _changed_streams = Stream_select ($read, $write, $except, 0);
if ($num _changed_streams > 0) {
foreach ($read as $r) {
$str = Fread ($r, 2048);
Fclose ($socket);
$socket = false;
return $str;
}
}
Usleep (100);
}
}

True asynchronous reading-using server IO multiplexing events to improve concurrency
Class get_data_event{

public $onMessage = null;
Private $str = ';

function __construct (& $server) {
$socket = Stream_socket_client ("tcp://test.xtgxiso.cn:80", $errno, $errstr, 6);
Stream_set_blocking ($socket, 0);
Fwrite ($socket, "get/sleep1.php http/1.0\r\nhost:test.xtgxiso.cn\r\naccept: */*\r\n\r\n");
$server->add_socket ($socket, Array ($this, ' read '));
}

Public function Read ($socket) {
while (1) {
$buffer = Fread ($socket, 1024);
if ($buffer = = = ' | | $buffer = = FALSE) {
Break
}
$this->str. = $buffer;
}
if ($this->onmessage && $this->str) {
Call_user_func ($this->onmessage, $this->str);
}
$this->str = ';
return false;
}

}

/**
* Single Process IO multiplexing Select
*/
Class Xtgxiso_server
{
Public $socket = false;
Public $master = Array ();
public $onConnect = null;
public $onMessage = null;
Public $other _socket_callback = Array ();

function __construct ($host = "0.0.0.0", $port =1215)
{
$this->socket = Stream_socket_server ("tcp://". $host ":". $port, $errno, $ERRSTR);
if (! $this->socket) die ($errstr.) -". $errno);
Stream_set_blocking ($this->socket,0);
$id = (int) $this->socket;
$this->master[$id] = $this->socket;
}

Public Function Add_socket ($socket, $callback) {
$id = (int) $socket;
$this->master[$id] = $socket;
$this->other_socket_callback[$id] = $callback;
}

Public Function run () {
$read = $this->master;
$receive = Array ();
echo "Start run...\n";
while (1) {
$read = $this->master;
echo "waiting...\n";
$mod _fd = @stream_select ($read, $_w = null, $_e = NULL, 60);
if ($mod _fd = = FALSE) {
Break
}
foreach ($read as $k => $v) {
$id = (int) $v;
if ($v = = = $this->socket) {
echo "New conn\n";
$conn = stream_socket_accept ($this->socket);
if ($this->onconnect) {
Call_user_func ($this->onconnect, $conn);
}
$id = (int) $conn;
$this->master[$id] = $conn;
else if (@ $this->other_socket_callback[$id]) {
Call_user_func_array ($this->other_socket_callback[$id], Array ($v));
} else {
echo "Read data\n";
if (!isset ($receive [$k])) {
$receive [$k]= "";
}
$buffer = Fread ($v, 1024);
echo $buffer. " \ n ";
if (strlen ($buffer) = = 0) {
if ($this->onclose) {
Call_user_func ($this->onclose, $v);
}
Fclose ($v);
$id = (int) $v;
unset ($this->master[$id]);
else if ($buffer = = FALSE) {
if ($this->onclose) {
Call_user_func ($this->onclose, $this->master[$key _to_del]);
}
Fclose ($v);
$id = (int) $v;
unset ($this->master[$id]);
} else {
$pos = Strpos ($buffer, "\r\n\r\n");
if ($pos = = False) {
$receive [$k]. = $buffer;
echo "Received:". $buffer. "; Not all package,continue recdiveing\n ";
}else{
$receive [$k]. = Trim (substr ($buffer, 0, $pos +4));
$buffer = substr ($buffer, $pos +4);
if ($this->onmessage) {
Call_user_func ($this->onmessage, $v, $receive [$k]);
}
$receive [$k]= ';
}
}
}
}
Usleep (10000);
}
}
}


$server = new Xtgxiso_server ();

$server->onconnect = function ($conn) {
echo "OnConnect--accepted". Stream_socket_get_name ($conn, True). "\ n";
};

$server->onmessage = function ($conn, $msg) use ($server) {
/*
$respone = "";//Response content
$respone = "http/1.1 ok\r\n";
$respone. = "server:openresty\r\n";
$respone. = "content-type:text/html; Charset=utf-8\r\n ";
$body = Time (). rand (111111,999999);
$len = strlen ($body);
$respone. = "Content-length: $len \ r \ n";
$respone. = "connection:close\r\n";
$respone. = "\r\n$body\r\n\r\n";
echo "OnMessage--". $msg. "\ n";
*/

Synchronous read
$respone = Get_data_blocking ();
Fwrite ($conn, $respone);

Asynchronous read
$respone = Get_data_unblocking ();
Fwrite ($conn, $respone);

Truly asynchronous
$data = new Get_data_event ($server);
$data->onmessage = function ($str) use ($conn) {
Fwrite ($conn, $STR);
};

};

$server->onclose = function ($conn) {
echo "OnClose--". "\ n";
};

$server->run ();
Third-party services sleep1.php code is relatively simple

<?php
Sleep (1);//Simulation time consuming
echo "OK";
With the code example above, we are commenting on the concurrency of the server by running synchronous reads, asynchronous reads, and truly asynchronous. The test method can write a test.html to simulate three concurrent.

<script src= "http://127.0.0.1:1215/?id=1" ></SCRIPT>
<script src= "http://127.0.0.1:1215/?id= 2 "></script>
<script src=" http://127.0.0.1:1215/?id=3 "></SCRIPT>
    The test found that the real asynchronous is concurrent, each request takes 1 seconds, so we can finally understand what is really non-blocking asynchronous programming, the key is in the shared IO multiplexing.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.