有时候我们的php程序需要和其他系统通讯,比如一个企业的官网提供产品溯源信息的查询,在后台网站就需要和企业的溯源系统或ERP系统通讯,此时就需要进行php的网络编程,php提供了一个sockets扩展,官网地址为:

http://nl3.php.net/manual/zh/intro.sockets.php

该扩展让我们有能力通过php直接操纵套接字socket,这样就可以和其他系统通讯了,我们使用socket在OSI网络模型的传输层以上工作,直接使用TCP、UDP提供的服务,因此可以使用它作为其他应用层协议的客户端,比如模拟HTTP客户端(浏览器),常见的smtp、pop、ftp都可以用它模拟,比较好玩的是可以使用它和允许TELNET的服务器交互,这些协议都是应用层协议所以它都可以交互,自定义的系统间通信就需要自定义协议了。

这里提供一个示例,用php开发一个简单的文件接收服务器,另一个php客户端程序展示如何和这个服务器程序通讯,代码如下。

服务器端程序:

<?php
/*** 本程序演示php网络编程:socket通讯 需要php开启php_sockets扩展* 这是一个简易的服务器程序,接收客户端发送的文件,保存后关闭* 通讯协议约定为:文件大小::文件扩展名::有效数据* 通讯结束标识符为:“-end-”* 在命令行或浏览器中执行均可,推荐命令行* 作者:云客【云游天下,作客四方】*//****配置****/
//要绑定监听的本机ip地址和端口
$address = '127.0.0.1';
$port = 81;error_reporting(E_ALL);//防止超时
set_time_limit(0);//开启绝对刷送,禁止缓冲内容
ob_implicit_flush();//创建套接字资源
if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
}
//绑定套接字到端口
if (socket_bind($sock, $address, $port) === false) {echo "socket_bind() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
}
//开始监听端口,参数5表示可以让5个连接请求在缓冲中排队
//排队的链接请求会在前一个连接断掉后才开始执行,该处缓冲排队数满五个后,后面的链接请求将直接忽略,客户端显示无法链接
//注意这个5并不是指可以并发进行5个链接,而是允许让5个后续链接进入排队
if (socket_listen($sock, 5) === false) {echo "socket_listen() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
}do {//程序运行到此处进行阻塞,就像暂停执行一样,一旦有请求进入,该函数停止阻塞,返回链接资源if (($client_sock = socket_accept($sock)) === false) {echo "socket_accept() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";break;}echo "[client connect start]\n";$data = ""; //接收的数据$data_size = -1; //接收的数据大小$received_size = 0; //实际接收的数据$ext_name = "txt"; //默认文件扩展名//开始与客户端交互do {//运行到该处产生阻塞,一旦有内容则停止阻塞状态,返回内容if (false === ($buf = socket_read($client_sock, 2048))) {echo "socket_read() failed: reason: " . socket_strerror(socket_last_error($client_sock)) . "\n";break 2; //读取不了就返回失败,此处的2会让客户端断掉链接后停止本模拟服务器}if ($data_size === -1) {//第一次接受数据,解析通讯协议$arr = explode("::", $buf, 3);$data_size = (int)$arr[0];$ext_name = $arr[1];$data .= $arr[2];$received_size += strlen($data);continue;}$data .= $buf;$received_size += strlen($buf);if ($data_size <= $received_size) {if ($data_size < $received_size) {$data = substr($data, 0, $data_size);}echo "received:" . $received_size . "/" . "total:" . $data_size;$talkback = "-end-"; //发送通讯结束标志socket_write($client_sock, $talkback, strlen($talkback));file_put_contents("servertest." . $ext_name, $data);break 2; //关闭服务器}echo $talkback = "received:" . $received_size . "\n";socket_write($client_sock, $talkback, strlen($talkback));} while (true);socket_close($client_sock);} while (true);socket_close($sock);
?>

客户端程序:

<?php
/*** 本程序演示php网络编程:socket通讯 需要php开启php_sockets扩展* 这是一个简易的客户端程序,向服务器发送文件* 通讯协议约定为:文件大小::文件扩展名::有效数据* 通讯结束标识符为:“-end-”* 在命令行或浏览器中执行均可,推荐命令行,需先开启服务器端* 作者:云客【云游天下,作客四方】*//****配置****/
$file = "yunke.jpg"; //待发送的文件
//服务器ip和端口号
$address = '127.0.0.1';
$port = 81;error_reporting(E_ALL);// 防止超时
set_time_limit(0);// 开启绝对刷送,不要缓冲输出
ob_implicit_flush(true);//创建套接字资源
if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";exit();
}
//打开到远程主机的链接
if (socket_connect($sock, $address, $port) === false) {echo "socket_connect() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";exit();
}//构造一个很大的待发送数据 大约10MB
/*
$data = "";
for ($i = 1; $i <= 10000000; $i++) {$data .= "data:" . $i;
}
$data = $data . $data . $data;
*/$data = file_get_contents($file);
$data_size = strlen($data);
$arr_temp = explode('.', $file);
$ext_name = end($arr_temp);
$sock_data = $data_size . "::" . $ext_name . "::" . $data;//发送数据给远程主机
while (true) {$sock_data_size = strlen($sock_data);$send_size = socket_write($sock, $sock_data, $sock_data_size);if ($send_size === false) {echo "send false:" . socket_strerror(socket_last_error($sock)) . "\n";socket_close($sock);echo "[client shutdown]\n";exit();}if ($send_size == $sock_data_size) {break;}$sock_data = substr($sock_data, $send_size);
}//读返回数据
while (true) {if (false === ($out = socket_read($sock, 2048))) {echo "socket_read() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";break 1;}echo "server: " . $out . "\n";if (substr($out, -5) == "-end-") { //约定结束标志break;}
}
//关闭套接字资源
socket_close($sock);
echo "[client shutdown]\nsend data:" . format($data_size);function format($byte = 0)
{if ($byte > 1024 * 1024) {return ceil($byte / (1024 * 1024)) . "MB";} elseif ($byte > 1024) {return ceil($byte / 1024) . "KB";} else {return $byte . " Byte";}
}

该示例展示通过一个TCP短链接的方式向服务器传送一个文件,在实际的项目中通讯模块不会这么简单,需要考虑更多的问题

比如:

是否需要长连接的方式(一个tcp链接里面多次来回传送数据)、数据校验防止损坏、不同系统间的大小端字节序问题、自定义通讯协议、粘包问题、超时处理、并发访问、流量控制、TCP封包解包等等

如果想深入了解php网络编程以上提到的这些都需要系统学习,推荐看一看workerman的实现

它是一个php写的socket服务器框架,帮助解决socket通讯问题,使用它可以建立一个自定义服务器等等
workerman官网地址为:http://www.workerman.net/

以下再提供两个查看服务器HTTP头和浏览器头的示例程序:

以下示例查看服务器返回的头信息,修改需要查看的服务器地址,然后在浏览器中访问该脚本即可:

<?php
error_reporting(E_ALL);// 防止超时
set_time_limit(0);// 开启绝对刷送,不要缓冲输出
ob_implicit_flush(true);$address = 'www.qq.com'; //要查看的服务器
$port=80;//创建套接字资源
if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";exit();
}
//打开到远程主机的链接
if (socket_connect($sock, gethostbyname($address), $port) === false) {echo "socket_connect() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";exit();
}//构造http头
$msg = "GET / HTTP/1.1 \r\n";
$msg .= "Host: {$address}\r\n";
$msg .= "Connection: Close\r\n\r\n";
//指示服务器发回完毕就断开,不必等等其他资源的链接
//如果没有该行会,服务器会一直等待我方继续发送数据,直到超时关闭
//而我方不会再发送,这个会让下面的socket_read函数互为等待,等很久//发送给远程主机
socket_write($sock, $msg, strlen($msg));$str="";
while ($out = @socket_read($sock, 2048*4)) {$str.=$out;
}
$str=explode("\r\n\r\n", $str);
$str=$str[0];
if($str)
{echo "<pre>\r\n".$str."\r\n</pre>";
}else{echo "nothing";
}//关闭套接字资源
socket_close($sock);

以下是查看浏览器头的示例,可以方便的查看浏览器发送的会话信息
首先确定关闭了80端口,然后修改本机的host文件,将想访问的网址定向到本机127.0.0.1地址,使用php命令行模式启动此脚本,然后使用浏览器访问已设置定向的网址即可,该程序会一直开启,如需关闭请在控制台使用ctrl+c组合键,程序如下:

<?php
error_reporting(E_ALL);//防止超时
set_time_limit(0);//开启绝对刷送,禁止缓冲内容
ob_implicit_flush();$address = '127.0.0.1';
$port = 80;//创建套接字资源
if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
}
//绑定套接字到端口
if (socket_bind($sock, $address, $port) === false) {echo "socket_bind() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
}
//开始监听端口,参数5表示可以让5个连接请求在缓冲中排队
//排队的链接请求会在前一个连接断掉后才开始执行,该处缓冲排队数满五个后,后面的链接请求将显示无法链接
//注意这个5并不是指可以并发进行5个链接,而是允许让5个后续链接进入排队
if (socket_listen($sock, 5) === false) {echo "socket_listen() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
}do {//程序运行到此处进行阻塞,就像暂停执行一样,一旦有请求进入,该函数停止阻塞,返回链接资源//可以使用socket_set_nonblock函数设置非阻塞模式if (($msgsock = socket_accept($sock)) === false) {echo "socket_accept() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";break;}//链接成功后在控制台显示提示echo "[client start ".date("Y-m-d H:i:s")."]\n\n";do {//运行到该处产生阻塞,一旦有内容则停止阻塞状态,返回内容if (false === ($buf = socket_read($msgsock, 2048*6))) {echo "socket_read() failed: reason: " . socket_strerror(socket_last_error($msgsock)) . "\n";break 2; //读取不了就返回失败,此处的2会让客户端断掉链接后停止本模拟服务器}$talkback ="HTTP/1.1 200 OK\r\n\r\n";$talkback .= date("Y-m-d H:i:s")."\nBrowser HTTP Headers:\n\n".$buf."\n";//向客户端显示该内容socket_write($msgsock, $talkback, strlen($talkback));//向服务器控制台显示该内容echo "$buf\n";break ; //中断本次与浏览器的链接} while (true);socket_close($msgsock);
} while (true);socket_close($sock);
?>

我是云客,【云游天下,做客四方】,联系方式见主页,欢迎转载,但须注明出处

php网络编程socket通讯相关推荐

  1. Python网络编程socket

    网络编程之socket 看到本篇文章的题目是不是很疑惑,what is this?,不要着急,但是记住一说网络编程,你就想socket,socket是实现网络编程的工具,那么什么是socket,什么是 ...

  2. 树莓派 Python 网络编程 (Socket入门)

    树莓派  Python 网络编程 (Socket入门) 什么是 Socket? Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络 ...

  3. 树莓派:入门(基础配置、GPIO、网络编程 Socket)

    树莓派在创客中越来越发挥重要的作用,树莓派的强大兼用性和功能丰富,得到 DIY 朋友的青睐.带大家认识目前最新的树莓派 3B+,从零基础到入门,到动手做有趣的应用. 本场 Chat 首先会带领大家入门 ...

  4. Python网络编程(Socket)

    Python网络编程(Socket) Python提供了两个访问级别的网络服务.在一个较低的水平,您可以访问底层操作系统的基本套接字支持,允许你实现面向连接和无连接协议的客户端和服务器 Python有 ...

  5. Java网络编程 Socket、ServerSocket 详解,方法介绍及完整代码示例

    Java网络编程 Socket.ServerSocket 详解,方法介绍及完整代码示例 概念 什么是网络编程? 网络编程是指编写运行在多个设备(计算机)的程序,这些设备通过网络连接起来.当这些通过网络 ...

  6. 网络编程socket之connect函数

    网络编程socket api存在一批核心接口,而这一批核心接口就是几个看似简单的函数,尽管实际上这些函数没有一个是简单.connect函数就是这些核心接口的一个函数,它完成主动连接的过程. conne ...

  7. Linux 网络编程——socket 网络编程

    文章目录 一.网络基础 TCP/UDP对比 TCP/IP协议族体系 socket IP地址 IP地址转化API inet_addr() inet_aton() inet_ntoa() inet_pto ...

  8. java网络编程socket\server\TCP笔记(转)

    java网络编程socket\server\TCP笔记(转) 2012-12-14 08:30:04|  分类: Socket |  标签:java  |举报|字号 订阅 1 TCP的开销 a  连接 ...

  9. 网络编程socket之accept函数

    网络编程socket之accept函数 摘要:对于服务器编程中最重要的一步等待并接受客户的连接,那么这一步在编程中如何完成,accept函数就是完成这一步的.它从内核中取出已经建立的客户连接,然后把这 ...

  10. 网络编程(socket)套接字之基于udp的套接字

    基于udp的网络编程 特点:不需要提前建立链接,每次收发都需要获取ip和端口 又称数据报协议,一次发送对应一次接收,不会产生粘包问题    不可靠传输,发送数据不需要回复ACK确认信息    没有链接 ...

最新文章

  1. Android系统移植与调试之-------如何修改Android设备添加重启、飞行模式、静音模式等功能(一)...
  2. 平凡的80后 不平凡的人生路
  3. velocity 模板引擎
  4. hibernate(七) hibernate中查询方式详解
  5. unity应用开发实战案例_「简历」STAR法则的实战应用,附手把手教学案例
  6. python单元测试mock_Python单元测试的Mock是怎么回事
  7. Spring Boot相关
  8. python开发环境管理:pip和virtualenv
  9. php如何递归算法,详细的介绍一下PHP递归算法_PHP教程
  10. 一步步构造自己的vue2.0+webpack环境
  11. python之Beautiflusoup操作
  12. 【ML小结8】降维与度量学习(KNN、PCA、因子分析、LDA)
  13. 变频器调试工具:ABB Drive Composer
  14. 如何申请MSN帐号和所有MSN后缀邮箱申请
  15. linux给cpu加压命令,Linux中cpupower命令起什么作用呢?
  16. iOS静态库SDK制作(包含支付宝支付、微信支付或其它第三方静态库)
  17. SSL/TLS一键配置工具-IISCrypto
  18. idea提交时忽略.class、.iml文件和文件夹或目录的方法
  19. Kawasaki川崎机械手c#二次开发dll
  20. 在Windows 7上使用Microsoft XPS Document Writer无法打印出XPS文档的问题

热门文章

  1. 简易打折,输入数量金额然后计算打折
  2. unbuntu 中部署jenkins
  3. 职场小白手收藏篇:职场应聘的面试技巧
  4. CSS的特殊性 (specificity)
  5. Mapped Statements collection already contains value
  6. JavaScript中三元一次函数的解法
  7. 中创向心力:如何把思想政治教育贯穿职业教育全过程?
  8. Mybatis---简单缓存了解
  9. word按backspace键不能删除问题
  10. 品牌鞋的运作,如何判别鞋的品牌真伪