PHP中的Socket编程

关于PHP socket的资料网上着实不多,或者讲的都不是很全面。为了更好地用PHP来处理socket,天堂皓月博客特地来简单总结一下其用法,尽量会做到深入浅出:)

文章结构:

  • Socket基础知识

  • 编写服务器

  • 编写客户端

  • 总结

通过这三部分你将会体验到Socket的魅力,并了解怎样去编写一个服务器,怎样通过Sockets连接到服务器,服务器怎样处理信息并将信息发送给相应的客户端。

不管你信不信,只要你用过PHP,就一定用过Sockets。HTTP服务器就是一个Socket服务器,浏览器就是客户端,也就是最简单的C/S模式。

Socket基础知识

我们可以把Socket当做是一种数据结构,客户端和服务器间通过这种数据结构来交换数据。服务器开始监听连接,当客户端想要连接服务器时,会通过服务器监听的端口开启一个会话,服务器收到客户端的请求后,建立连接完毕,然后继续监听下一次连接。

要产生一个Socket,你我们需要三个变量:一个协议(protocol)、一个socket类型(socket type)和一个公共协议类型(common protocol type)。下面将会详细介绍各个部分的具体内容。

协议

  • AF_INET:这是大多数用来产生socket的协议,使用TCP或UDP来传输,用在IPv4的地址

  • AF_INET6:与上面类似,不过是来用在IPv6的地址

  • AF_UNIX:本地协议,使用在Unix和Linux系统上,它很少使用,一般都是当客户端和服务器在同一台及其上的时候使用

Socket类型

  • SOCK_STREAM:这个协议是按照顺序的、可靠的、数据完整的基于字节流的连接。这是一个使用最多的socket类型,这个socket是使用TCP来进行传输。

  • SOCK_DGRAM:这个协议是无连接的、固定长度的传输调用。该协议是不可靠的,使用UDP来进行它的连接。

  • SOCK_SEQPACKET:这个协议是双线路的、可靠的连接,发送固定长度的数据包进行传输。必须把这个包完整的接受才能进行读取。

  • SOCK_RAW:这个socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议。(ping、traceroute使用该协议)

  • SOCK_RDM:这个类型是很少使用的,在大部分的操作系统上没有实现,它是提供给数据链路层使用,不保证数据包的顺序

公共协议

  • ICMP:互联网控制消息协议,主要使用在网关和主机上,用来检查网络状况和报告错误信息

  • UDP:用户数据报文协议,它是一个无连接,不可靠的传输协议

  • TCP:传输控制协议,这是一个使用最多的可靠的公共协议,它能保证数据包能够到达接受者那儿,如果在传输过程中发生错误,那么它将重新发送出错数据包。

在PHP中我们使用socket_create()函数来产生一个Socket。socket_create()函数运行成功返回一个包含Socket的资源类型,如果没有成功则返回false。

1 resource socket_create(int protocol, int socketType, int commonProtocol);

PHP提供了很多操作Socket的函数。现在我们来看一个例子,了解PHP是如何产生、接受和监听一个socket。

:::PHP<?php
$commonProtocol = getprotobyname(“tcp”);
$socket = socket_create(AF_INET, SOCK_STREAM, $commonProtocol);
socket_bind($socket, ‘localhost’, 1337);
socket_listen($socket);
// More socket functionality to come
?>

我们来详细解释一下上面这个程序(基于行号):

第二行:使用公共协议名字来获取一个协议类型。在这里使用的是TCP公共协议,如果你想使用UDP或者ICMP协议,就应该把 getprotobyname()函数的参数改为“udp”或“icmp”。我们也可以不使用getprotobyname()函数而是直接指定 SOL_TCP或SOL_UDP。

第三行:产生一个Socket并且返回一个Socket资源的实例。

第四行:有了一个Socket资源的实例以后,就必须把Socket绑定到一个IP地址和某一端口上。在这里绑定socket到本地计算机(127.0.0.1)的1337端口。

第五行:然后就需要监听所有进来的socket连接。

这时,我们就需要了解一下PHP中Socket函数的使用方法了。官方手册的介绍非常不错(猛戳这个链接),下面只是简单列举几个最常用的。

  • socket_accept() 接受一个Socket连接

  • socket_bind() 把socket绑定在一个IP地址和端口上

  • socket_close() 关闭一个socket资源

  • socket_connect() 开始一个socket连接

  • socket_create_listen() 在指定端口打开一个socket监听

  • socket_create() 产生一个socket,相当于产生一个socket的数据结构

  • socket_get_option() 获取socket选项

  • socket_getpeername() 获取远程主机的ip地址

  • socket_getsockname() 获取本地socket的ip地址

  • socket_listen() 监听由指定socket的所有连接

  • socket_read() 读取指定长度的数据

  • socket_readv() 读取从分散/聚合数组过来的数据

  • socket_recv() 从socket里结束数据到缓存

  • socket_recvfrom() 接受数据从指定的socket,如果没有指定则默认当前socket

  • socket_recvmsg() 从iovec里接受消息

  • socket_select() 多路选择

  • socket_send() 这个函数发送数据到已连接的socket

  • socket_sendmsg() 发送消息到socket

  • socket_sendto() 发送消息到指定地址的socket

  • socket_set_block() 在socket里设置为块模式

  • socket_set_nonblock() socket里设置为非块模式

  • socket_set_option() 设置socket选项

  • socket_shutdown() 这个函数允许你关闭读、写、或者指定的socket

  • socket_write() 写数据到socket缓存

关于PHP Socket的基础知识就介绍到这里,还有不明白的可查看官方手册。下面介绍编写一个Socket服务器。

编写服务器

现在我们把第一个例子完善,使其能够监听一个指定的Socket并处理用户的连接。

:::PHP<?php$commonProtocol = getprotobyname("tcp");$socket = socket_create(AF_INET, SOCK_STREAM, $commonProtocol);
socket_bind($socket, 'localhost', 1337);
socket_listen($socket);// Accept any incoming connections to the server$connection = socket_accept($socket);if($connection)
{
   socket_write($connection, "You have connected to the socket...\n\r");
}?>

注意这不是一个Web页面,如果你尝试使用Web浏览器来运行这个脚本,那么很有可能它会超过PHP运行30秒的限时。当然你可以使用下面的代码来设置一个无限的运行时间

set_time_limit(0);

但最好的办法还是直接使用命令提示符来运行:

php server.php

但截至目前,上面的服务器端有三个问题

  1. 它不能接受多个连接。

  1. 它只完成唯一的一个命令。

  1. 你不能通过Web浏览器连接这个服务器。

在上一个代码的基础上再改进,使用下面的代码来做新服务器端:

:::PHP
<?php
// Set up our socket 
$commonProtocol = getprotobyname("tcp");$socket = socket_create(AF_INET, SOCK_STREAM, $commonProtocol);
socket_bind($socket, 'localhost', 1337);
socket_listen($socket);
// Initialize the buffer 
$buffer = "NO DATA";while(true)
{
    // Accept any connections coming in on this socket    $connection = socket_accept($socket);    printf("Socket connected\r\n");
    // Check to see if there is anything in the buffer    if($buffer != "")
    {        printf("Something is in the buffer...sending data...\r\n");
        socket_write($connection, $buffer . "\r\n");        printf("Wrote to socket\r\n");
    }    else
    {        printf("No Data in the buffer\r\n");
    }
    // Get the input    while($data = socket_read($connection, 1024, PHP_NORMAL_READ))
    {        $buffer = $data;
        socket_write($connection, "Information Received\r\n");        printf("Buffer: " . $buffer . "\r\n");
    }
    socket_close($connection);    printf("Closed the socket\r\n\r\n");
}
?>

这段程序初始化一个socket并且打开一个缓冲区收发数据。然后服务器开始等待连接,此时一旦产生一个连接,服务器将 打印“Socket connected”。然后服务器检查缓冲区,如果缓冲区里有数据,服务器就把这些数据发送到连接的计算机客户端。然后服务器等待接收信息,并把接收到的 信息保存,然后让连接的客户端知道信息接收成功后,服务器将关闭连接。连接关闭后,服务器将开始下一次处理连接的循环。

编写客户端

解决上面提到的第二个问题还是比较容易的。我们需要一个连接到服务器的页面来处理数据并发送到服务器。

我们来看下面的代码:

:::PHP<?php// Create the socket and connect $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);$connection = socket_connect($socket,’localhost’, 1337);while($buffer = socket_read($socket, 1024, PHP_NORMAL_READ))
{    if($buffer == “NO DATA”)
    {        echo(“<p>NO DATA</p>”);        break;
    }    else
    {        // Do something with the data in the buffer 
        echo(“<p>Buffer Data: “ . $buffer . “</p>”);
    }
}echo(“<p>Writing to Socket</p>”);// Write some test data to our socketif(!socket_write($socket, “SOME DATA\r\n”))
{    echo(“<p>Write failed</p>”);
}// Read any response from the socketwhile($buffer = socket_read($socket, 1024, PHP_NORMAL_READ))
{    echo(“<p>Data sent was: SOME DATA<br> Response was:” . $buffer . “</p>”);
}echo(“<p>Done Reading from Socket</p>”);?>

这个例子的客户端连接到服务器后,客户端读取数据。如果这是客户端第一次连接服务器,服务器将发送“NO DATA”给客户端。如果客户端收到“NO DATA”说明其连接成功,客户端发送它的数据到服务器并等待服务器响应。一旦客户端接收到服务器的响应,客户端将把响应内容输出到屏幕上。

总结

如果还想深入了解PHP Socket,建议阅读更多的第三方资料或到PHP官方查询官方文档。今天就介绍到这里,如果有错误欢迎指正。


转载于:https://my.oschina.net/forMemory/blog/368276

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值