php socket网络编程基础知识(一):开篇
说明
- 虽然我们普通的web编程中很少用到网络编程,但实际上我们一直都在用,例如nginx和php-fpm之间的通讯就是网络通讯,也会发现他们的一些配置参数,其实就是网络编程中一些函数的参数。
- 我们说是通讯,想当然的就是两台机器之间的通讯,但实际上同一台机器上同样可以通过回环来通讯交互,就像是nginx和php-fpm既可以部署在同一机器上,也可以负载均衡部署在多机器上。
- php本身是提供了网络通讯方面的功能的,但相关的文档大都没有翻译成中文,而且文档说明和举例也比较少和抽象,需要有一定基础的才能看懂,导致更少的人去用了
- 如果学习这方面的话,只看文档时不行的,需要查询大量的关联资料才能理解,查询资料可以不局限在php方面,其它语言也都有网络通讯相关,原理都是共通的。
- 这里记录下自己的一些知识点简单的总结。
相关的需求
我们只有在解决实际问题时,才能真正理解各个方法的用法含义,那我们假设如果要实现类似web端的客服与顾客的聊天,会遇到哪些问题或者应该怎么解决:
- 虽然是两者聊天,但实际上两者并不是直接聊天,而是通过中间服务器的中转,也就是
客服---服务器
建立通讯、顾客---服务器
建立通讯,类似发送信件,需要通过邮局来进行转发。 - 这也就要求服务器至少同时接入两个客户端(客户和顾客),但服务器怎么能同时处理两个呢?目前我们能想到的应该就是用多进程或多线程解决了,当一个顾客接入开启一个进程来处理与顾客的通讯,主进程继续检测客服是否有接入,如果客服也接入则同样开启进程处理。
- 然后就单独
客服---服务器
这一个通信来说,读和写会不会冲突呢,客服需要接收消息,但是我们根本不知道服务器(顾客)什么时候发送消息,那理所当然的做法是用while循环一直检测服务端发送的消息,那这里就会卡住,都去在循环中检测读消息了那我要怎么发送消息呢,目前我们能想到的解决方法还是开新进程或线程来解决读写冲突的问题。 - 我们的通讯一般还需要每隔一段时间就发送一个心跳包,否则如果长时间不通讯的话,系统会关闭此连接。这又出现问题了,我们的程序读、写都处理不过来了,心跳要怎么发送呢,我们能想到的方法还是开新进程或线程来单独发送心跳包。
- 上面说的问题,只想想就头痛了,进程、线程官方文档都介绍的比较少,更不要说还要考虑进程、线程他们之间的通信了,但这确实是一种解决方法。
- 那单进程就无法处理了吗?并不是,我们可以用系统提供的select类似的IO多路复用方法,此方法可以通过系统内核来监控接入、读取、写入等事件,当发生了事件就会通知你,然后去处理就可以了,这样在一个进程中就可以完成上述的操作,但一个进程所接收的总量毕竟有限,所以要提高并发时还是会用到多进程来处理,但此时的逻辑会比上方所说的简单很多,至于心跳包的问题,我们则可以通过定时器信号来解决,也无需多开一个新进程或线程。
- 这里还有一个刚开始学习时,我自己非常迷惑的地方,在学习各种示例时,不管是发送的还是接收的消息都是写死的,但是我们实际的需求是需要用户填写,那中间如何插入进去呢?这相当于惯性思维,一提到用户填写立刻想到post传输,然后就有些混乱冲突了,但实际上对于web端聊天场景来说他们之间的传输是用的websocket,顾客点击发送事件中直接调用
ws.send
类似方法发送消息,服务端收到消息触发读取消息事件,在事件中转发给客服即可。而对于类似app推送消息的场景来说,后台填写数据确实是需要post传输到web服务端,然后web服务端接收到post数据后再通过调用send类似方法发送给socket服务端,socket服务端接收到消息后再向各个socket客户端广播消息,由于php脚本执行完就关闭了,所以web服务端到socket服务端同样会关闭,但并没有什么影响,每次都重新连接就是了,我们只需要保证socket服务端和客户端维持长连接就行了,web服务端只有后台想发送推送信息时连接一下socket服务端就行了。 - 所以我们要实现上方的功能,需要学习的知识点为:
- Socket基础
- Stream流基础
- 多进程
- 信号
- IO模型
相关的php功能
- Socket函数,最基础的调用,用法和纯C的非常相似
- Stream函数,php做的socket调用的进一步封装,比上面调用更加方便
- PCNTL函数 ,socket编程一般是离不开多进程及信号等功能
- POSIX函数,进程信息,用户、组等管理,信号发送等
- Libevent函数,事件驱动库
相关资料
- PHP多进程初探系列文章,写的非常不错
- Workerman,纯php写的socket通讯的封装,我们可以查看其源码来了解各个socket相关函数具体是怎么用的。
- workerman源码解读,这位同学分析的挺全面的。
- Python 中的 Socket 编程(指南),即便没学过python,但是理解socket的功能后看关键字也能理解大部分内容。
缘由
原先有项目接触过与java网络通信相关的,当时用php没有搞定,最后还是用他们的java相关sdk做的,所以一直想补充这方面的知识,但是一直都没有看下去,这次的起因是这样的:
- 看python的基础知识,正好看到pack、协程、select这块
- 那php也有相应的pack、yield函数等,对应着看其中的差异(其实对照其它语言更能加深理解)
- php的yied相关,并没有进一步封装,而swoole号称协程方面处理的很好
- swoole用C写的,但自己C功底不好,所以想先看类似的用纯php写的Workerman
- Workerman很简洁,写的也非常好,里面有些函数自己看不懂,所以就对应着查看相关的了
关联
- php socket网络编程基础知识(二):socket函数
- php socket网络编程基础知识(三):stream函数
- php socket网络编程基础知识(四):多进程
- php socket网络编程基础知识(五):信号(未完成)
- php socket网络编程基础知识(六):IO模型(未完成)
- php socket网络编程基础知识(七):libevent(未完成)
注意
- 这个前几篇文章早已写过,一直存草稿里,打算全写完再发出来,但后来由于自己已经转JAVA开发了,所以后续的章节都没有写完,目前是没有计划再写了,可能等学习完JAVA的
Netty
后会再总结,时隔好久又翻到了存草稿里的这几篇文章,还是先发出来供参考吧