PHP Socket编程进阶指南

学习准备

Linux 或者 Mac 环境;

安装有 Sockets 扩展;

了解 TCP/IP 协议。

socket函数只是PHP扩展的一部分,编译PHP时必须在配置中添加 配置项来启用。

如果自带的PHP没有编译scokets扩展,可以下载相同版本的源码,进入 使用 编译安装。

socket系列函数

socket服务端/客户端流程:

图中所示流程在任何编程语言里都是通用的。

server端

接下来我们写一个简单的单进程TCP服务器:

sockettcpserver.php

说明:例子里我们先创建了一个TCP server,然后循环等待客户端连接。收到客户端连接后,循环解析来自客户端的消息。

例子里使用 作为消息结束符,如果一次没有接收到完整消息,就循环读取,直到遇到结束符;读取完一条完整消息后,向客户端发送收到的消息,然后清空消息,准备下一次接收。

我们在命令行里运行服务端:

新开终端使用telnet连接:

我们发送了一条消息,服务端这边会收到:

接下来,我们使用socket写一个自己的tcp客户端。

client端

下面的例子很简单,创建客户端,连接服务端,发送消息,读取完后就结束了。

sockettcpclient.php

我们先在原来的telnet终端页面输入 退出连接,因为此时我们的服务端还只能接受一个客户端连接。然后运行自己写的客户端:

socket_select

上面的例子里,我们的tcp服务端仅能接受一个客户端连接。怎么能做到支持多个客户端连接呢?常用的有:

多进程

多线程

I/O复用,使用select、poll、epoll等技术

多进程+I/O复用

本节里我们使用第三种方法,即I/O复用。技术实现层面则是使用PHP提供的socket_select系统调用来实现。

I/O复用使得程序能同时监听多个文件描述符。实现I/O复用的系统调用主要的有select、poll、epoll。

接下来看实例:

socket_select.php

我们先使用 关闭上一次运行的TCP server,然后运行新写的server:

新开终端telnet客户端:

再打开终端新开一个telnet客户端,我们来看服务端的输出:

此时我们的服务端就不受客户端连接数限制了。

注意点: 1、使用了socket_select后,解析消息的地方不能再是死循环,否则造成阻塞。

select 函数监视的文件描述符分为3类,分别是 writefds, readfds, exceptfds,调用之后select函数就会阻塞,直到有文件描述符就绪(有数据可读,可写或者except),或者超时(timeout指定等待时间,如果立即返回设为null即可),函数返回;当select函数返回之后,可以通过遍历 fdset来找到就绪的描述符。

2、socket系统调用最大支持1024个客户端连接,如果需要更大的客户端连连,则需要使用poll、epoll等技术。本文不做讲解。

socketsetoption

该函数用来设置socket选项,比如设置端口复用。函数原型:

示例:

该小节不是本文重点,该函数大家了解即可,需要设置的时候能知道怎么调用。顺便提一下,端口复用技术是用来解决"惊群"问题的,大家感兴趣可以看看博文:Linux网络编程“惊群”问题总结 - https://www.cnblogs.com/Anker/p/7071849.html 。

函数参考

这些PHP官方手册里都有,贴出来供大家快速查阅。

stream_socket系列函数

stream_socket系列函数相当于是socket函数的进一步封装。使用该系类函数能简化我们的编码。

和 返回的句柄可以由 , , , 以及 函数调用。

server端

我们先看一下函数原型。

streamsocketserver:

如果是udp服务,flags指定为 。 另外, 由 创建,例如:

streamsocketaccept:

接下来我们使用 系列函数写一个tcp server。

tcp server

示例: streamsocketserver.php

代码相比使用纯 函数少了很多。

运行:

客户端使用telnet:

udp server

udp服务端不需要listen操作。

运行:

客户端使用 netcat:

如果没有netcat需要安装:

客户端

上面我们都是用的 和 来连接服务端,接下来我们使用 系列函数编写tcp/udp客户端。

简单示例

stream_socket系列函数写client非常简单:

udp客户端仅需要修改tcp为udp。

stream_select

系列函数使用 实现I/O复用,本质都是select系统调用。

接下来我们写两个示例,第一个示例和上面使用 实现的类似,第二个则是监听了客户端读写事件,从而实现了类似telnet的功能,相信大家会感兴趣的。

同时监听socket和连接socket

使用stream_select可以实现IO复用,使得单进程程序也能支持同时处理多个客户端连接。示例:

运行服务端并随后运行telnet客户端:

可以同时支持多个客户端。从例子可以看出来, 和 用法相同。

同时处理网络连接和用户输入

下面的例子使用stream_select实现了客户端程序运行后,支持命令行界面手动实时输入与服务端进程交互:

例子里,我们把 和 使用stream_select监听文件描述符的变化情况,当有文件描述符就绪,函数会返回,从而执行我们逻辑代码。

先运行tcp服务端程序stream_select.php,然后运行该客户端程序:

程序一直会等待我们的输入,除非输入quit退出。

函数参考

总结

本文主要和大家讲解了 PHP Socket 编程相关知识。通过学习本文,大家学到了如下内容:

熟悉 socket 系列函数使用

熟悉 stream_socket 系列函数使用

熟悉 I/O 复用

如何使用 socket 系列函数实现 TCP 服务端和客户端

如何使用 socket_select 实现 I/O 多路复用

如何使用 stream_socket 系列函数实现TCP服务端和客户端

如何使用 stream_select 实现 I/O 多路复用

也给大家留一个问题:

如何基于PHP多进程Master-Worker模型实现支持I/O复用的TCP server?

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180711G08PKD00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券