当前位置: 首页 > 后端技术 > PHP

PHP网络编程小白系列——接受阻塞模型

时间:2023-03-29 17:48:11 PHP

之前我们实现了一个简单的C/S交互,接下来自然要介绍和学习一个常见的网络交互模型。Accept阻塞模型是一个比较老的模型,但是里面包含了很多有趣的知识,比如阻塞/非阻塞、锁、超时重传……服务端程序acceptSever.php”。$ct_data。PHP_EOL;fwrite($conn,"收到$ct_size字节数据./r/n");fclose($conn);}fclose($socket);}}新套接字服务器(2000);客户端程序acceptClient.php默认运行phpsocket_client。.log记录服务器返回的接收结果数据,效果如下:这种情况很容易理解,这里不再赘述。然后,使用telnet命令同时开启多个客户端,你会发现服务器一次只处理一个客户端,如图:其他需要稍后“排队”;这就是blockingIO的特点,这种模式的弱点非常明显,效率极低。B>只打开socket_client.php第29行注释掉的代码,再次运行phpsocket_client.php测试。客户端会打印一个W,服务端也会打印一个R,之后两个程序都卡住了。为什么是这样?分析逻辑后,你会发现这是因为客户端在发送终结符之前向服务器请求了数据;并且服务器还向客户端询问终结符,因为它没有收到终结符。造成僵局。之所以只打一个W和R,是因为fread默认是屏蔽的。要解决这个死锁,必须打开socket_client.php第17行的注释代码,给socket设置0.1秒的超时时间,再次运行,会发现每0.1秒出现一个W和R,然后正常结束,并且服务器返回的接收结果数据也正常记录。可见fread默认是阻塞的,我们在编程的时候一定要特别注意,如果不设置timeout的话,很容易出现死锁。C>只开启14行注释将脚本设置为非阻塞,运行phpsocket_client.php测试,结果与案例A基本相同,唯一不同的是socket.log没有记录返回的数据,这个是因为当我们非阻塞的时候,客户端是可以继续执行的,而不需要等待服务端的响应结果。执行debug时,读取到的数据还是空的,所以socket.log也是空的。这里我们可以看出客户端运行在阻塞模式和非阻塞模式下的区别。当然,如果客户端不关心接收结果,可以使用非阻塞模式来获得最大效率。D>运行phpsocket_client.php就是把上面的逻辑连续运行10次,这个没有问题;但是很奇怪的是,如果用39-45行的代码,用popen同时开10个进程运行,会导致server端死循环,很奇怪!后来经过排查,发现只要是popen打开的进程创建的连接,就会导致fread或者socket_read直接返回空字符串,导致死循环,查阅PHP源码后发现,PHP的popen和fread函数根本不是C语言的原生函数,里面插入了大量的php_stream_*实现逻辑。初步估计是bug导致的Socket连接中断。解决方法是打开socket_server.php中第33行的代码。如果连接中断,会跳出循环,但是这样会丢失很多数据,这个问题需要特别注意!AcceptBlockingModelConclusion本来想写一篇关于socket网络编程和网络交互模型过渡的文章——过程篇,但是文章篇幅不会太多,所以打算以后再放——番外篇.然后这篇文章介绍了经典的网络模型——Acceptblockingmodel,里面也涉及到很多知识点,挺有意思的,但是也提到了这个模型效率比较低,所以一开始就介绍效率比较高的下一篇文章。I/O多路复用网络模型,敬请期待。