summarize
In order to better understand, network programming and write a high-performance service, we need to spend some time to understand the whole process of the server processing the client and understand some key terms. We originally wanted to add some basic theoretical knowledge in this article, fearing that too much space is not conducive to reading, so we will reissue some basic knowledge later and then get down to business.
Theory
This article mainly introduces the basic steps of realizing a network server, and the code will be reproduced once in the practice.
First step
We need to create a socket, bind server port (bind), listen port (listen), and use stream_socket_server function in PHP to complete the above three steps.
Second step
Enter while loop, block on accept operation, wait for client connection to enter. At this time, the program will go to sleep until a new client initiates connect to the server, and the operating system will wake up the process. The accept function returns the socket of the client connection
Third step
Fread is used to read the data in the socket of the client. After receiving the data, the server program processes it and then uses fwrite to send a response to the client. Long-connected services will continue to interact with clients, while short-connected services will normally close upon receiving a response.
Practice
Here we use code to implement the next basic process. Before we start writing code, we will introduce some php functions that may be used in our code for your understanding.
Function
stream_socket_server
stream_socket_accept
call_user_func
is_callable
fread
Click on the function for usage
Code
Cut the crap and start straight away ~
<? php
class Worker{
//Monitor socket
protected $socket = NULL;
//Connection Event Callback
public $onConnect = NULL;
//Receive Message Event Callback
public $onMessage = NULL;
public function __construct($socket_address) {
}
public function run(){
}
}
$worker = new Worker('tcp://0.0.0.0:9810');
//A connection event callback was registered in advance
$worker->onConnect = function ($data) {
Echo' new connection is coming', $data, PHP_EOL;
};
//An event callback to receive a message was registered in advance
$worker->onMessage = function ($conn, $message) {
};
$worker->run();
According to the previous process, we need to monitor the port+address
public function __construct($socket_address) {
//Listening Address+Port
$this->socket=stream_socket_server($socket_address);
}
The next step is to block the accept operation and wait for the client connection to enter. At this time, the program will go to sleep until a new client initiates connect to the server, and the operating system will wake up the process.
public function run(){
While (true) {// loop monitor
$client = stream_socket_accept($this->socket); //Blocking Monitoring on Server Side
}
}
When a new connection enters the wake-up process and triggers a connection event callback
public function run(){
While (true) {// loop monitor
$client = stream_socket_accept($this->socket); //Blocking Monitoring on Server Side
if(! Empty ($ client)&&is _ callable ($ this-> onconnect)) {//socket connection succeeded and is our callback
//Callback of the connection that triggered the event
call_user_func($this->onConnect,$client);
}
}
}
The connection callback here actually triggers the following code here that has prepared the class library before.
$worker->onConnect = function ($data) {
Echo' connection event:', $data, PHP_EOL;
};
When the connection is successful, fread is used to obtain the content of the client and trigger the event of receiving the message.
public function run(){
While (true) {// loop monitor
$client = stream_socket_accept($this->socket); //Blocking Monitoring on Server Side
if(! Empty ($ client)&&is _ callable ($ this-> onconnect)) {//socket connection succeeded and is our callback
//Callback of the connection that triggered the event
call_user_func($this->onConnect,$client);
}
//read client content from connection
$buffer=fread($client,65535); //Parameter 2: Maximum number of bytes read in buffer
//Data is normally read. Triggering a message receiving event to respond
if(! empty($buffer) && is_callable($this->onMessage)){
//Message receiving event of trigger time
call_user_func($this->onMessage,$this,$client,$buffer); //current object, current connection, received message of "event to receive message"
}
}
}
At this point, the basic network service reception is basically completed, and a response is required to the request. Take http request as an example, here is a method of HTTP response (http://127.0.0.1:9810)
class Worker{
...
...
...
public function send($conn,$content){
$http_resonse = "HTTP/1.1 200 OK\r\n";
$http_resonse .= "Content-Type: text/html; charset=UTF-8\r\n";
$http_resonse .= "Connection: keep-alive\r\n";
$http_resonse .= "Server: php socket server\r\n";
$http_resonse .= "Content-length: ".strlen($content)."\r\n\r\n";
$http_resonse .= $content;
fwrite($conn, $http_resonse);
}
}
Respond to http requests when triggering receive message events
$worker->onMessage = function ($server,$conn, $message) {
Echo' Message from Client:', $message,PHP_EOL;
$server->send($conn,' message from server');
};
This is the end ~, complete codeThrough train
Disadvantages
Only one connection can be processed at a time, and simultaneous processing of multiple connections is not supported.