基于Socket实现简单的回声服务器

上一篇文章是对socket编程的入门,这次我们基于socket实现一个简单的收发消息的服务。

实现思路:

先说服务端:

  1. 接受客户端的连接

  2. 读取客户端发送过来的信息

  3. 将接受到信息发送给客户端

客户端:

  1. 首先连接到服务端

  2. 读取用户输入

  3. 将用户输入的信息发送给服务端

  4. 发送之后将会接收到服务端返回来的信息

由于PHP没有原生的从命令行接收用户输入的函数,所以这里通过以下方式来实现:
基于Socket实现简单的回声服务器’/dev/stdin’,这个是linux的标准输入,其实这个函数就是把linux的标准输入,重定向到我们的后端PHP程序了。然后我们的PHP程序就接收到了用户的输入,接着就可以把这个输入发送到回声服务程序的服务端了。

通过上面一篇文章,我们已经对于创建套接字的流程有了一定的了解,在这里就不多说这些了。

接下来开始服务端的实现:

echo_server.php:
基于Socket实现简单的回声服务器
代码解读:

第1处:这里直接使用了上一篇文章介绍的stream_socket_server函数,可以一次性的完成socket的创建、绑定以及监听。

第2处:开始监听我们创建的套接字(至于这里为什么加上@,因为stream_socket_accept函数如果一定时间内没有收到客户端的连接的话,会报一个warning)

第3处:通过fread函数,读取输入缓冲区,一次读取1024个字节

第4处:将读取到的字符写入输入缓冲,从而发送到客户端。

通过上面的程序我们已经实现了回声服务程序的服务端。

接下来我们可以运行一下,会发现我们的echo_server.php已经进入阻塞状态,等待客户端连接。

接着实现客户端:

echo_client.php
基于Socket实现简单的回声服务器
代码解读:

第1处:调用我们的重定向标准输入函数,调用此函数之后,如果不输入任何字符,程序是不会执行到下一行的,因为这里会被阻塞。

第2处:如果我们输入了q这个字符,将跳出while循环,紧接着会执行fclose,关闭连接。这里要注意一下,客户端关闭连接之后,会向服务端发送一个信号,告诉服务端我已经断开连接了,服务端接受到之后将关闭此客户端的连接。

第3处:将读取到的输入信息写入缓冲区,从而发送到服务端。

第4处到第5处是要重点讲解的内容。

此处为什么不直接通过fread函数一次性读取服务端返回的消息呢?

以下是对于这个问题的解答:

对于每一个socket,都有一个发送缓冲区和接收缓冲区。如果我们发送的数据足够大,则可能分为两次发送。也就是说fwrite之后,我们发送的字符有可能被分成两部分发送了,而服务端的代码是在不断的接收数据,然后返回数据。

所以客户端可能出现如下情况:发送一次字符之后,客户端尚未接收到全部的数据就调用了fread函数,从而打印多次。

所以对于这个问题最好的解决方法就是,我们客户端是能够提前知道要接收的字符大小的,所以这里通过strlen函数获取要接收的数据大小,如果不足这个大小则继续读取,直到满足条件之后再输出。

下面是程序运行的效果:
基于Socket实现简单的回声服务器
基于Socket实现简单的回声服务器
以上则是我们的回声服务程序,记得自己动手练习哦,眼过千遍不如手过一遍!

本人会持续分享一些关于编程以及编程自学相关的文章,记录自己的自学编程之路。同时希望自己的分享能够帮助一些对编程感兴趣以及正在编程道路上的朋友。欢迎大家关注我的公众号「阿毛的Coding之路 」。
基于Socket实现简单的回声服务器