Maison >développement back-end >tutoriel php >PHP implémente un socket local (Unix Domain Socket) pour la programmation système
Le contenu partagé avec vous dans cet article concerne le socket local (Unix Domain Socket) dans la programmation système PHP. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer
The Socket. L'API a été conçue à l'origine pour résoudre les communications réseau, et plus tard, une technologie appelée socket local (Unix Domain Socket) a été dérivée. Comme son nom l'indique, le socket local ne prend en charge que deux processus locaux pour communiquer entre eux, bien que le domaine Internet. Socket peut également réaliser une communication inter-processus locale via l'adresse de bouclage locale (127.0.0.1), car le socket local n'a pas besoin de passer par la pile de protocoles réseau, paquet Déballage, calcul des sommes de contrôle et autres opérations, elle présente donc certains avantages par rapport aux prises réseau en termes d'efficacité. Étant donné que les sockets locaux ont des performances élevées, une stabilité et une prise en charge de la communication inter-processus non liée au sang, les sockets locaux sont également l'un des mécanismes IPC (Inter-Process Communication) les plus largement utilisés.
Comparaison des performances entre Nginx et PHP-FPM en utilisant les sockets réseau (127.0.0.1:9000) et en utilisant les sockets locaux
En général, nous laissons PHP-FPM surveiller 127.0.0.1:9000. Évidemment, Nginx et PHP-FPM communiquent via des sockets réseau en ce moment. En fait, si Nginx s'exécute sur le même serveur que PHP-FPM, nous pouvons également le laisser. PHP-FPM écoute les sockets locaux. Ensuite, nous ferons une simple comparaison des performances de ces deux méthodes.
Ici, mon Nginx démarre deux processus de travail
[root@localhost ~]# ps -ef | grep nginx root 1838 1 0 22:48 ? 00:00:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf nginx 1839 1838 0 22:48 ? 00:00:00 nginx: worker process nginx 1840 1838 0 22:48 ? 00:00:00 nginx: worker process root 1851 1797 0 22:49 pts/0 00:00:00 grep nginx
Utilisation Les configurations des sockets Web, Nginx et PHP-FPM sont les suivantes :
Script de test de stress test.php
<?php phpinfo();
Résultats des tests de résistance :
Regardons la communication entre Nginx et PHP-FPM à l'aide de sockets locaux. Les configurations de Nginx et PHP-FPM sont légèrement modifiées :
<.>
Résultats des tests de résistance :
Les tests ci-dessus sont tous obtenus après plusieurs tests de résistance. D'après les résultats, nous pouvons voir que la prise locale est meilleure que le réseau. Le QPS des sockets est en moyenne supérieur de plus de 100, ce qui est fondamentalement conforme à nos attentes.
Programmation de socket local avec PHP
En fait, la programmation des sockets locaux de PHP est fondamentalement la même que la programmation des sockets réseau, sauf que les paramètres passés sont différents.
PHP fournit deux ensembles d'API pour la programmation de sockets, l'un est la série de méthodes socket_*, qui a été démontrée dans notre précédente série d'articles, et l'autre est stream_socket_ * série de méthodes, et cette dernière est plus pratique à utiliser ici, nous utilisons cette dernière pour démontrer.
stream_socket_* Liste de méthodes :
•stream_socket_accept — 接受由 stream_socket_server 创建的套接字连接 •stream_socket_client — Open Internet or Unix domain socket connection •stream_socket_enable_crypto — Turns encryption on/off on an already connected socket •stream_socket_get_name — 获取本地或者远程的套接字名称 •stream_socket_pair — 创建一对完全一样的网络套接字连接流 •stream_socket_recvfrom — Receives data from a socket, connected or not •stream_socket_sendto — Sends a message to a socket, whether it is connected or not •stream_socket_server — Create an Internet or Unix domain server socket •stream_socket_shutdown — Shutdown a full-duplex connection
Veuillez vous référer au manuel PHP pour les méthodes spécifiques. Voici une démonstration directe du code :
Code côté serveur :
<?php //stream_server.php $sockfile = '/dev/shm/unix.sock'; // 如果sock文件已存在,先尝试删除 if (file_exists($sockfile)) { unlink($sockfile); } $server = stream_socket_server("unix://$sockfile", $errno, $errstr); if (!$server) { die("创建unix domain socket fail: $errno - $errstr"); } while(1) { $conn = stream_socket_accept($server, 5); if ($conn) { while(1) { $msg = fread($conn, 1024); if (strlen($msg) == 0) //客户端关闭 { fclose($conn); break; } echo "read data: $msg"; fwrite($conn, "read ok!"); } } } fclose($server);
Code client :
<?php //stream_client.php $client = stream_socket_client("unix:///dev/shm/unix.sock", $errno, $errstr); if (!$client) { die("connect to server fail: $errno - $errstr"); } while(1) { $msg = fread(STDIN, 1024); if ($msg == "quit\n") { break; } fwrite($client, $msg); $rt = fread($client, 1024); echo $rt . "\n"; } fclose($client);
运行
server端:
[root@localhost html]# php stream_server.php read data: hello unix domain socket read data: are you ok? read data: I'm fine! PHP Warning: stream_socket_accept(): accept failed: Connection timed out in /usr/share/nginx/html/stream_server.php on line 13 PHP Warning: stream_socket_accept(): accept failed: Connection timed out in /usr/share/nginx/html/stream_server.php on line 13 PHP Warning: stream_socket_accept(): accept failed: Connection timed out in /usr/share/nginx/html/stream_server.php on line 13 PHP Warning: stream_socket_accept(): accept failed: Connection timed out in /usr/share/nginx/html/stream_server.php on line 13 PHP Warning: stream_socket_accept(): accept failed: Connection timed out in /usr/share/nginx/html/stream_server.php on line 13 PHP Warning: stream_socket_accept(): accept failed: Connection timed out in /usr/share/nginx/html/stream_server.php on line 13
client端:
[root@localhost html]# php stream_client.php hello unix domain socket read ok! are you ok? read ok! I'm fine! read ok! ^C
以上是一个最简单的本地套接字的代码演示,细心的读者可能注意到了server端报的warning,服务器如果长时间没有客户端过来连接,超过了stream_socket_accept 方法设置的timeout,服务器端便会报这个警告,事实上,真正的服务端代码是不会是像这样写的,因为这种方式同一时间只能处理一个客户端连接,如果要实现并发,一种方式就是使用IO多路复用,如同 socket_* 系列方法中有socket_select 方法 (参考系列文章第一篇http://blog.csdn.net/zhang197093/article/details/77366407),stream_socket_* 系列方法提供了 stream_select 方法来实现多路复用,使用方法也很相似。
int stream_select ( array &$read , array &$write , array &$except , int $tv_sec [, int $tv_usec = 0 ] )
The stream_select() function accepts arrays of streams and waits for them to change status. Its operation is equivalent to that of the socket_select() function except in that it acts on streams.
详细的方法介绍请参考PHP手册 : http://php.net/manual/zh/function.stream-select.php
优化后的代码如下:
<?php //stream_server.php $sockfile = '/dev/shm/unix.sock'; // 如果sock文件已存在,先尝试删除 if (file_exists($sockfile)) { unlink($sockfile); } $server = stream_socket_server("unix://$sockfile", $errno, $errstr); if (!$server) { die("创建unix domain socket fail: $errno - $errstr"); } $listen_reads = array($server); $listen_writes = array(); $listen_excepts = NULL; while(1) { $can_reads = $listen_reads; $can_writes = $listen_writes; $num_streams = stream_select($can_reads, $can_writes, $listen_excepts, 0); if ($num_streams) { foreach ($can_reads as &$sock) { if ($server == $sock) { $conn = stream_socket_accept($server, 5); //此时一定存在客户端连接,不会有超时的情况 if ($conn) { // 把客户端连接加入监听 $listen_reads[] = $conn; $listen_writes[] = $conn; } } else { $msg = fread($sock, 1024); //此时一定是可读的 if (strlen($msg) == 0) //读取到0个字符,说明客户端关闭 { fclose($sock); // 从sock监听中移除 $key = array_search($sock, $listen_reads); unset($listen_reads[$key]); $key = array_search($sock, $listen_writes); unset($listen_writes[$key]); echo "客户端关闭\n"; } else { echo "read data: $msg"; // 是否可写 if (in_array($sock, $can_writes)) { fwrite($conn, "read ok!"); } } } } } } fclose($server);
此时这个server就不会有前面那个Warning了,并且支持并发
[root@localhost html]# php stream_server.php read data: hello world read data: hello unix domain socket read data: harry up read data: read data: read data: I'm another client 客户端关闭 客户端关闭 read data: I'm the third client 客户端关闭
That‘s all!
相关推荐:
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!