资讯专栏INFORMATION COLUMN

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

darkbaby123 / 2546人阅读

摘要:而之所以只打出一个和,是因为默认是阻塞的。那么本篇就介绍了经典网络模型阻塞模型,里面也涉及到了蛮多的知识点,比较有意思,但是也提到了该模型效率较低,所以下一篇开始我会介绍效率更高的复用的网络模型,敬请期待。

前面我们实现了一个简单的 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复用的网络模型,敬请期待。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/29130.html

相关文章

  • PHP 网络编程小白系列 —— 前言

    摘要:这跟国内文化学习路径编程意识都有关系,当然还有一个重要原因就是没有比较详尽的资料无从下手,那么通过这系列文章我希望小白能够走近网络编程。 我们应该要明白一点:但凡涉及网络的事务,一定要经过网络的各个层次,PHP程序员可能更多地是在服务端的应用层打交道很少接触应用层下面的传输层、网络层。这跟国内 PHP文化、学习路径、编程意识都有关系,当然还有一个重要原因就是没有比较详尽的资料无从下手,...

    walterrwu 评论0 收藏0
  • PHP 网络编程小白系列 —— Socket 编程入门

    摘要:在这个时刻,服务程序被惊醒并且为客户提供服务对客户的请求作出适当的反应。为了方便这种模型的网络编程,年代初,由联合了其他几家公司共同制定了一套下的网络编程接口,即规范,它不是一种网络协议而是一套开放的支持多种协议的下的网络编程接口。 这篇文章将会介绍一下 Socket 编程中相关的 PHP 函数,并简单实现一个 C/S 的交互 Socket 简介 Socket 的官方解释:在网络编程中...

    DevWiki 评论0 收藏0
  • PHP回顾之socket编程

    摘要:如果你想体验原味编程,用开头的比较适合否则建议使用流函数。有关流的知识,请参考本人之前的博文回顾之流。接下来我们用流函数实现一个简单的客户端和服务端。流函数中的和两个函数是我们想要的。本文目的是简要介绍中的编程,行文到此已经达到目的。 转载请注明文章出处: https://tlanyan.me/php-review... PHP回顾系列目录 PHP基础 web请求 cookie w...

    tomorrowwu 评论0 收藏0
  • PHP并发IO编程之路

    摘要:下文如无特殊声明将使用进程同时表示进程线程。收到数据后服务器程序进行处理然后使用向客户端发送响应。现在各种高并发异步的服务器程序都是基于实现的,比如。 并发 IO 问题一直是服务器端编程中的技术难题,从最早的同步阻塞直接 Fork 进程,到 Worker 进程池/线程池,到现在的异步IO、协程。PHP 程序员因为有强大的 LAMP 框架,对这类底层方面的知识知之甚少,本文目的就是详细介...

    Riddler 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<