利用 PHP Socket 相关函数实现 TCP、UDP 端口监听。
需要注意,下面的示例代码中没有处理 Socket 错误。实际应用场景中每一步 Socket 的连接、写入、读取都需要进行错误判断和处理,相应的函数 socket_connect、socket_write、socket_read 以及 socket_bind、socket_listen 返回 false 时,需要调用 socket_last_error() 获取最新的 socket 错误号 $errno,并通过 socket_strerror($errno) 获取错误号对应的能够阅读的错误描述信息。
PHP Socket TCP 发送数据示例
$host = '127.0.0.1'; $port = '81'; $message = 'Hello TCP Server'; function send_tcp_message($host, $port, $message) { $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); @socket_connect($socket, $host, $port); $num = 0; $length = strlen($message); do { $buffer = substr($message, $num); $ret = @socket_write($socket, $buffer); $num += $ret; } while ($num < $length); $ret = ''; do { $buffer = @socket_read($socket, 1024, PHP_BINARY_READ); $ret .= $buffer; } while (strlen($buffer) == 1024); socket_close($socket); return $ret; } $ret = send_tcp_message($host, $port, $message);
PHP Socket TCP 接收数据示例
创建一个 Server 接收 TCP 连接,需要先监听一个端口。
$host = '127.0.0.1'; $port = '81'; $callback = 'echo'; function receive_tcp_message($host, $port, $callback) { $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); // socket_bind() 的参数 $host 必传, 由于是监听本机, 此处可以固定写本机地址 // 注意: 监听本机地址和内网地址效果不一样 @socket_bind($socket, $host, $port); @set_time_limit(0); // 绑定端口之后调用监听函数, 实现端口监听 @socket_listen($socket, 5); // 接下来只需要一直读取, 检查是否有来源连接即可, 如果有, 则会得到一个新的 socket 资源 while ($child = @socket_accept($socket)) { // 休息 1 ms, 也可以不用休息 usleep(1000); if (false === socket_getpeername($child, $remote_host, $remote_port)) { @socket_close($child); continue; } // 读取请求数据 // 例如是 http 报文, 则解析 http 报文 $request = ''; do { $buffer = @socket_read($child, 1024, PHP_BINARY_READ); if (false === $buffer) { @socket_close($child); continue 2; } $request .= $buffer; } while (strlen($buffer) == 1024); // 此处省略如何调用 $callback $response = $callback($remote_host, $remote_port, $request); if (!strlen($response)) { // 至少返回含有一个空格的字符串 $response = ' '; } // 因为是 TCP 链接, 需要返回给客户端处理数据 $num = 0; $length = strlen($response); do { $buffer = substr($response, $num); $ret = @socket_write($child, $buffer); $num += $ret; } while ($num < $length); // 关闭 socket 资源, 继续循环 @socket_close($child); } } // 客户端来的任何请求都会打印到屏幕上 receive_tcp_message($host, $port, $callback); // 如果程序没有出现异常,该进程会一直存在
有一个快捷的函数 socket_create_listen($port),创建、绑定、监听一步到位。
PHP Socket UDP 发送数据示例
$host = '127.0.0.1'; $port = '82'; $message = 'Hello UDP Server'; function send_udp_message($host, $port, $message) { $socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); @socket_connect($socket, $host, $port); $num = 0; $length = strlen($message); do { $buffer = substr($message, $num); $ret = @socket_write($socket, $buffer); $num += $ret; } while ($num < $length); socket_close($socket); // UDP 是一种无链接的传输层协议, 不需要也无法获取返回消息 return true; } send_udp_message($host, $port, $message);
PHP Socket UDP 接收数据示例
$host = '127.0.0.1'; $port = '82'; $callback = 'echo'; function receive_udp_message($host, $port, $callback) { $socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); @socket_bind($socket, $host, $port); @set_time_limit(0); while (true) { usleep(1000); $ret = @socket_recvfrom($socket, $request, 16384, 0, $remote_host, $remote_port); if ($ret) { $callback($remote_host, $remote_port, $request); } // 不需要返回给客户端任何消息, 继续循环 } } // 客户端来的任何请求都会打印到屏幕上 receive_udp_message($host, $port, $callback); // 如果程序没有出现异常,该进程会一直存在
PHP Socket 相关函数
- socket_accept — Accepts a connection on a socket
- socket_bind — Binds a name to a socket
- socket_clear_error — Clears the error on the socket or the last error code
- socket_close — Closes a socket resource
- socket_cmsg_space — Calculate message buffer size
- socket_connect — Initiates a connection on a socket
- socket_create_listen — Opens a socket on port to accept connections
- socket_create_pair — Creates a pair of indistinguishable sockets and stores them in an array
- socket_create — Create a socket (endpoint for communication)
- socket_get_option — Gets socket options for the socket
- socket_getpeername — Queries the remote side of the given socket which may either result in host/port or in a Unix filesystem path, dependent on its type
- socket_getsockname — Queries the local side of the given socket which may either result in host/port or in a Unix filesystem path, dependent on its type
- socket_import_stream — Import a stream
- socket_last_error — Returns the last error on the socket
- socket_listen — Listens for a connection on a socket
- socket_read — Reads a maximum of length bytes from a socket
- socket_recv — Receives data from a connected socket
- socket_recvfrom — Receives data from a socket whether or not it is connection-oriented
- socket_recvmsg — Read a message
- socket_select — Runs the select() system call on the given arrays of sockets with a specified timeout
- socket_send — Sends data to a connected socket
- socket_sendmsg — Send a message
- socket_sendto — Sends a message to a socket, whether it is connected or not
- socket_set_block — Sets blocking mode on a socket resource
- socket_set_nonblock — Sets nonblocking mode for file descriptor fd
- socket_set_option — Sets socket options for the socket
- socket_shutdown — Shuts down a socket for receiving, sending, or both
- socket_strerror — Return a string describing a socket error
- socket_write — Write to a socket