A brief introduction to php's socket communication

What is TCP/IP, UDP?

TCP/IP (Transmission Control Protocol/Internet Protocol), the Transmission Control Protocol/Internet Protocol, is an industry standard set of protocols designed for wide area networks (WANs).
UDP (User Data Protocol, User Data Protocol) is a protocol corresponding to TCP. It is one of the TCP/IP protocol family.
Here is a diagram showing the relationship of these protocols.
figure 1
The TCP/IP protocol suite includes the transport layer, the network layer, and the link layer. Now you know the relationship between TCP/IP and UDP.
Where is the socket?
In Figure 1, we don't see the shadow of Socket, so where is it? Or use pictures to speak, at a glance.
figure 2

What is Socket?

Socket is a middleware abstraction layer that communicates between the application layer and the TCP/IP protocol suite. It is a set of interfaces. In the design mode, Socket is actually a facade mode, which hides the complex TCP/IP protocol family behind the Socket interface. For users, a set of simple interfaces is all that is needed. Let the Socket organize the data to meet the specified requirements. protocol.
How it works Let's
How it works.jpg
  start with the server side. The server first initializes the Socket, then binds it to the port, listens to the port, calls accept to block, and waits for the client to connect. At this time, if a client initializes a Socket, and then connects to the server (connect), if the connection is successful, then the connection between the client and the server is established. The client sends a data request, the server receives the request and processes the request, then sends the response data to the client, the client reads the data, and finally closes the connection, and an interaction ends.

socket related functions:

socket_accept() accepts a socket connection
socket_bind() binds the socket to an IP address and port
socket_clear_error() clears socket errors or the last error code
socket_close() closes a socket resource
socket_connect() starts a socket connection
socket_create_listen() Open a socket on the specified port and listen
socket_create_pair() Generate a pair of indistinguishable sockets into an array
socket_create() Generate a socket, which is equivalent to generating a socket data structure
socket_get_option() Get socket options
socket_getpeername() Get remote similar host ip address
socket_getsockname() gets the ip address of the local socket
socket_iovec_add() adds a new vector to a scatter/aggregate array
socket_iovec_alloc() This function creates an iovec data structure capable of sending, receiving, reading and writing
socket_iovec_delete() deleting an already allocated iovec
socket_iovec_fetch() returns the data of the specified iovec resource
socket_iovec_free() releases an iovec resource
socket_iovec_set() sets the new value of the iovec data
socket_last_error() Get the last error code of the current socket
socket_listen() Monitor all connections from the specified socket
socket_read() Read the data of the specified length
socket_readv() Read the data from the scatter/aggregate array
socket_recv() End the data from the socket To the cache
socket_recvfrom() Accepts data from the specified socket, if not specified, defaults to the current socket
socket_recvmsg() Receives messages from iovec
socket_select() Multiplexing
socket_send() This function sends data to the connected socket
socket_sendmsg() Sends messages to socket
socket_sendto() send message to socket at specified address
socket_set_block() set block mode in socket
socket_set_nonblock() set non-block mode in
socket socket_set_option() set socket option
socket_shutdown() This function allows you to close read, write, Or the specified socket
socket_strerror() returns the detailed error of the specified error number
socket_write() writes data to the socket buffer
socket_writev() writes data to the scatter/aggregate array

Case: socket communication demonstration

Service-Terminal:

<?php
//确保在连接客户端时不会超时
set_time_limit(0);

$ip = '127.0.0.1';
$port = 1935;

/*
 +-------------------------------
 *    @socket通信整个过程
 +-------------------------------
 *    @socket_create
 *    @socket_bind
 *    @socket_listen
 *    @socket_accept
 *    @socket_read
 *    @socket_write
 *    @socket_close
 +--------------------------------
 */

/*----------------    以下操作都是手册上的    -------------------*/
if(($sock = socket_create(AF_INET,SOCK_STREAM,SOL_TCP)) < 0) {
    echo "socket_create() 失败的原因是:".socket_strerror($sock)."\n";
}

if(($ret = socket_bind($sock,$ip,$port)) < 0) {
    echo "socket_bind() 失败的原因是:".socket_strerror($ret)."\n";
}

if(($ret = socket_listen($sock,4)) < 0) {
    echo "socket_listen() 失败的原因是:".socket_strerror($ret)."\n";
}

$count = 0;

do {
    if (($msgsock = socket_accept($sock)) < 0) {
        echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n";
        break;
    } else {
        
        //发到客户端
        $msg ="测试成功!\n";
        socket_write($msgsock, $msg, strlen($msg));
        
        echo "测试成功了啊\n";
        $buf = socket_read($msgsock,8192);
        
        
        $talkback = "收到的信息:$buf\n";
        echo $talkback;
        
        if(++$count >= 5){
            break;
        };
        
    
    }
    //echo $buf;
    socket_close($msgsock);

} while (true);

socket_close($sock);
?>

保存、执行此文件。运行netstat -ano可以查看端口情况,我的是1935端口
端口处于LISTENING表示已经监听了。接下来我们只要运行客户端程序即可连接上。
客户端:

<?php
error_reporting(E_ALL);
set_time_limit(0);
echo "<h2>TCP/IP Connection</h2>\n";

$port = 1935;
$ip = "127.0.0.1";

/*
 +-------------------------------
 *    @socket连接整个过程
 +-------------------------------
 *    @socket_create
 *    @socket_connect
 *    @socket_write
 *    @socket_read
 *    @socket_close
 +--------------------------------
 */

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket < 0) {
    echo "socket_create() failed: reason: " . socket_strerror($socket) . "\n";
}else {
    echo "OK.\n";
}

echo "试图连接 '$ip' 端口 '$port'...\n";
$result = socket_connect($socket, $ip, $port);
if ($result < 0) {
    echo "socket_connect() failed.\nReason: ($result) " . socket_strerror($result) . "\n";
}else {
    echo "连接OK\n";
}

$in = "Ho\r\n";
$in .= "first blood\r\n";
$out = '';

if(!socket_write($socket, $in, strlen($in))) {
    echo "socket_write() failed: reason: " . socket_strerror($socket) . "\n";
}else {
    echo "发送到服务器信息成功!\n";
    echo "发送的内容为:<font color='red'>$in</font> <br>";
}

while($out = socket_read($socket, 8192)) {
    echo "接收服务器回传信息成功!\n";
    echo "接受的内容为:",$out;
}


echo "关闭SOCKET...\n";
socket_close($socket);
echo "关闭OK\n";
?>

执行服务端和客户端返回信息,至此客户端已经连接上服务端了

代码详解

// 设置一些基本的变量
$host = "192.168.1.99";
$port = 1234;
// 设置超时时间
set_time_limit(0);
// 创建一个Socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not createsocket\n");
//绑定Socket到端口
$result = socket_bind($socket, $host, $port) or die("Could not bind tosocket\n");
// 开始监听链接
$result = socket_listen($socket, 3) or die("Could not set up socketlistener\n");
// accept incoming connections
// 另一个Socket来处理通信
$spawn = socket_accept($socket) or die("Could not accept incomingconnection\n");
// 获得客户端的输入
$input = socket_read($spawn, 1024) or die("Could not read input\n");
// 清空输入字符串
$input = trim($input);
//处理客户端输入并返回结果
$output = strrev($input) . "\n";
socket_write($spawn, $output, strlen ($output)) or die("Could not write output\n");
// 关闭sockets
socket_close($spawn);
socket_close($socket);

下面是其每一步骤的详细说明:
1.第一步是建立两个变量来保存Socket运行的服务器的IP地址和端口.你可以设置为你自己的服务器和端口(这个端口可以是1到65535之间的数字),前提是这个端口未被使用.

// 设置两个变量
$host = "192.168.1.99";
$port = 1234;

2.在服务器端可以使用set_time_out()函数来确保PHP在等待客户端连接时不会超时.

// 超时时间
set_time_limit(0);

3.在前面的基础上,现在该使用socket_creat()函数创建一个Socket了—这个函数返回一个Socket句柄,这个句柄将用在以后所有的函数中.

// 创建Socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket\n");

第一个参数”AF_INET”用来指定域名;
第二个参数”SOCK_STREM”告诉函数将创建一个什么类型的Socket(在这个例子中是TCP类型)

因此,如果你想创建一个UDP Socket的话,你可以使用如下的代码:

// 创建 socket
$socket = socket_create(AF_INET, SOCK_DGRAM, 0) or die("Could not create socket\n");

4.一旦创建了一个Socket句柄,下一步就是指定或者绑定它到指定的地址和端口.这可以通过socket_bind()函数来完成.

// 绑定 socket to 指定地址和端口
$result = socket_bind($socket, $host, $port) or die("Could not bind to socket\n");

5.当Socket被创建好并绑定到一个端口后,就可以开始监听外部的连接了.PHP允许你由socket_listen()函数来开始一个监听,同时你可以指定一个数字(在这个例子中就是第二个参数:3)

// 开始监听连接
$result = socket_listen($socket, 3) or die("Could not set up socket listener\n");

6.到现在,你的服务器除了等待来自客户端的连接请求外基本上什么也没有做.一旦一个客户端的连接被收到,socket_accept()函数便开始起作用了,它接收连接请求并调用另一个子Socket来处理客户端–服务器间的信息.

//接受请求链接
// 调用子socket 处理信息
$spawn = socket_accept($socket) or die("Could not accept incoming connection\n");

This sub-socket is now available for subsequent client-server communication.
7. When a connection is established, the server waits for the client to send some input, which can be obtained by the socket_read() function, and Assign it to PHP's $input variable.

// 读取客户端输入
$input = socket_read($spawn, 1024) or die("Could not read input\n");

The second parameter of socket_read is used to specify the number of bytes read, you can use it to limit the size of the data obtained from the client.
Note: the socket_read function will always read the shell client data until it encounters n, t or 0 character. The PHP script treats this character as the end of the input.
8. Now the server has to process the data sent by the client (the processing in this example only includes the input of the data and the return to the client). This part can be done by the socket_write() function (making it possible to send a data stream back to the client by the communication socket)

// 处理客户端输入并返回数据
$output = strrev($input) . "\n";
socket_write($spawn, $output, strlen ($output)) or die("Could not write output\n");

9. Once the output is returned to the client, both parent/child sockets should be terminated by the socket_close() function

// 关闭 sockets
socket_close($spawn);
socket_close($socket);

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324688108&siteId=291194637