PHP Socket 实现 TCP、UDP 报文的发送与接收

利用 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 相关函数

  1. socket_accept — Accepts a connection on a socket
  2. socket_bind — Binds a name to a socket
  3. socket_clear_error — Clears the error on the socket or the last error code
  4. socket_close — Closes a socket resource
  5. socket_cmsg_space — Calculate message buffer size
  6. socket_connect — Initiates a connection on a socket
  7. socket_create_listen — Opens a socket on port to accept connections
  8. socket_create_pair — Creates a pair of indistinguishable sockets and stores them in an array
  9. socket_create — Create a socket (endpoint for communication)
  10. socket_get_option — Gets socket options for the socket
  11. 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
  12. 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
  13. socket_import_stream — Import a stream
  14. socket_last_error — Returns the last error on the socket
  15. socket_listen — Listens for a connection on a socket
  16. socket_read — Reads a maximum of length bytes from a socket
  17. socket_recv — Receives data from a connected socket
  18. socket_recvfrom — Receives data from a socket whether or not it is connection-oriented
  19. socket_recvmsg — Read a message
  20. socket_select — Runs the select() system call on the given arrays of sockets with a specified timeout
  21. socket_send — Sends data to a connected socket
  22. socket_sendmsg — Send a message
  23. socket_sendto — Sends a message to a socket, whether it is connected or not
  24. socket_set_block — Sets blocking mode on a socket resource
  25. socket_set_nonblock — Sets nonblocking mode for file descriptor fd
  26. socket_set_option — Sets socket options for the socket
  27. socket_shutdown — Shuts down a socket for receiving, sending, or both
  28. socket_strerror — Return a string describing a socket error
  29. socket_write — Write to a socket

作者: 袖之欢

科技改变生活,编程改变世界。

发表评论

电子邮件地址不会被公开。 必填项已用*标注