博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PHP 网络编程小白系列 —— Accept 阻塞模型
阅读量:7089 次
发布时间:2019-06-28

本文共 1911 字,大约阅读时间需要 6 分钟。

前面我们实现了一个简单的 C/S 交互,接下来我们自然要介绍和学习一下常见的网络交互模型

Accept 阻塞模型是一种相对古老的模型,不过里面蕴含了许多有趣的知识,比如阻塞/非阻塞、锁、超时重传...

服务端程序 acceptSever.php

" . $ct_data . PHP_EOL; fwrite($conn, "Received $ct_size byte data./r/n"); fclose($conn); } fclose($socket); }}new SocketServer(2000);

客户端程序 acceptClient.php

代码解析

首先,解释一下以上的代码逻辑:客户端 acceptClient.php 循环发送数据,最后发送结束符;服务端 accept Server.php 使用 accept 阻塞方式接收 socket 连接,然后循环接收数据,直到收到结束符,返回结果数据(接收到的字节数)客户端收到服务器返回的数据,写入日志。虽然逻辑很简单,但是其中有几种情况很值得分析一下:

A> 默认情况下,运行 php socket_client.php test,客户端打出 10 个 W,服务端打出若干个 R 后面是接收到的数据,socket.log 记录下服务端返回的接收结果数据,效果如下:

图片描述
这种情况很容易理解,不再赘述。然后,使用 telnet 命令同时打开多个客户端,你会发现服务器一个时间只处理一个客户端,如图所示:
图片描述
其他需要在后面“排队”;这就是阻塞 IO 的特点,这种模式的弱点很明显,效率极低。

B> 只打开 socket_client.php 第 29 行的注释代码,再次运行 php socket_client.php test 客户端打出一个 W,服务端也打出一个 R,之后两个程序都卡住了。这是为什么呢,分析逻辑后你会发现,这是由于客户端在未发送结束符之前就向服务端要返回数据;而服务端由于未收到结束符,也在向客户端要结束符,造成死锁。而之所以只打出一个 W 和 R,是因为 fread 默认是阻塞的。要解决这个死锁,必须打开 socket_client.php 第 17 行的注释代码,给 socket 设置一个 0.1 秒的超时,再次运行你会发现隔 0.1 秒出现一个 W 和 R 之后正常结束,服务端返回的接收结果数据也正常记录了。可见 fread 缺省是阻塞的,我们在编程的时候要特别注意,如果没有设置超时,就很容易会出现死锁。

C> 只打开 14 行注释设置脚本为非阻塞,运行 php socket_client.php test,结果基本和情况 A 相同,唯一不同的是 socket.log 没有记录下返回数据,这是因为当我们非阻塞下客户端不必等待接收到服务器的响应结果就可以继续往下执行,当执行到 debug 的时候,读取的数据还是空的,所以 socket.log 也是空的。这里可以看出客户端运行在阻塞和非阻塞模式的区别,当然在客户端不在乎接受结果的情况下,可以使用非阻塞模式来获得最大效率。

D> 运行 php socket_client.php 是连续运行 10 次上面的逻辑,这个没什么问题;但是很奇怪的是如果你使用 39 - 45 行的代码,用 popen 同时开启 10 个进程来运行,就会造成服务器端的死循环,十分怪异!后来经调查发现只要是用 popen 打开的进程创建的连接会导致 fread 或者 socket_read 出错直接返回空字串,从而导致死循环,查阅 PHP 源代码后发现 PHP 的 popen 和 fread 函数已经完全不是 C 原生的了,里面都插入了大量的 php_stream_* 实现逻辑,初步估计是其中的某个 bug 导致的 Socket 连接中断所导致的,解决方法就是打开 socket_server.php 中 33 行的代码,如果连接中断则跳出循环,但是这样一来就会有很多数据丢失了,这个问题需要特别注意!

Accept 阻塞模型 结语

本来想着写一篇关于 socket 网络编程 和 网络交互模型的过渡篇—— 进程篇的,但是篇幅不是很多独立成篇有点鸡肋,所以打算把它放到后面——番外篇。那么本篇就介绍了 经典网络模型——Accept 阻塞模型,里面也涉及到了蛮多的知识点,比较有意思,但是也提到了该模型效率较低,所以下一篇开始我会介绍 效率更高的I/O复用的网络模型,敬请期待。

转载地址:http://ntiql.baihongyu.com/

你可能感兴趣的文章
RS485中继器电路(转)
查看>>
控制台打印二叉树
查看>>
Android 5.x特性概览四
查看>>
【python】——小程序之电话薄
查看>>
Atitit.iso格式蓝光 BDMV 结构说明
查看>>
MySQL的create table as 与 like区别(转)
查看>>
Linux学习历程(持续更新整理中)
查看>>
Linux查看物理CPU个数、核数、逻辑CPU个数
查看>>
软件设计模式详解:OCP原则
查看>>
Apache服务器常规操作
查看>>
qt cef嵌入web
查看>>
Java程序员面试失败的5大原因
查看>>
过滤器(Filter)
查看>>
外观模式
查看>>
Webmin|Linux管理员远程管理工具
查看>>
【温故而知新-Javascript】比较 undefined 和 null 值
查看>>
CentOS中iptables防火墙 开放80端口方法
查看>>
Kafka 在行动:7步实现从RDBMS到Hadoop的实时流传输
查看>>
[内核]Linux workqueue
查看>>
云计算开始。。。
查看>>