通信需要服务端和客户端组成:
服务端:使用php初始化socket然后绑定一个端口,对端口进行监听。调用accept阻塞,等待客户端连接。
客户端:客户端初始化一个socket,然后连接服务器,如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。
客户端—服务端是可以彼此交互的应用程序。客户端和服务端之间的交互需要连接。Socket编程负责的就是为应用程序之间建立可进行交互的连接。
Socket连接过程
根据连接启动的方式以及本地套接字要连接的目标,套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认。
(1)服务器监听:是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。
(2)客户端请求:是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
(3)连接确认:是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。
socket原理可以参考下面的流程图:
下面通过一个服务端--客户端的代码实例来简单实现一下socket通信整个过程
1. 其服务端代码:
<?php set_time_limit(0); //限制执行时间 0为不限制 $ip = '127.0.0.1'; $port = 8001;//端口 /** socket通信整个过程 socket_create //创建一个套接字 socket_bind //给套接字绑定 ip 和端口 socket_listen //监听套接字上的连接 socket_accept //接受一个socket连接 socket_read //接收客户端 发送的数据 socket_write //将数据写到 socket 缓存 向客户端发送 socket_close //关闭套接字资源 */ if(($sock = socket_create(AF_INET,SOCK_STREAM,SOL_TCP)) < 0) { echo "socket_create() 失败的原因是:".socket_strerror($sock)."\n"; } if(($ret = socket_bind($sock,$ip,$port)) < 0) { echo "socket_bind() 失败的原因是:".socket_strerror($ret)."\n"; } if(($ret = socket_listen($sock,4)) < 0) { echo "socket_listen() 失败的原因是:".socket_strerror($ret)."\n"; } $count = 0; do { if (($msgsock = socket_accept($sock)) < 0) { echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n"; break; } else { //发到客户端 $msg ="测试成功!\n"; socket_write($msgsock, $msg, strlen($msg)); echo "测试成功了啊\n"; $buf = socket_read($msgsock,8192); $talkback = "收到的信息:$buf\n"; echo $talkback; if(++$count >= 5){ break; }; } //echo $buf; socket_close($msgsock); } while (true); socket_close($sock); ?>
运行php 文件,运行后 ,应该看不见结果 , 可以使用 netstat -a 查看 8001 端口是否被占用。参见下图。
<?php header("content-type:text/html;charset=utf-8"); error_reporting(E_ALL); set_time_limit(0); echo "socket通信客户端\n"; $port = 8001;//端口 $ip = "127.0.0.1";//ip /*** socket连接整个过程 socket_create //建立一个socket 连接 socket_connect // 开始一个socket连接 连接服务端 socket_write //将数据写入缓存 向服务端发送 socket_read// 读取服务端的结果 socket_close // 关闭套接字资源 **/ $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if ($socket < 0) { echo "socket_create() failed: reason: " . socket_strerror($socket) . "\n"; }else { echo "OK.<br/>\n"; } echo "试图连接 '$ip' 端口 '$port'...\n"; $result = socket_connect($socket, $ip, $port); if ($result < 0) { echo "socket_connect() failed.\nReason: ($result) " . socket_strerror($result) . "\n"; }else { echo "连接OK<br/>\n"; } $in = '<xml> <TX> <REQUEST_SN>请求序列码</REQUEST_SN> <CUST_ID>客户号</CUST_ID> <USER_ID>操作员号</USER_ID> <PASSWORD>密码</PASSWORD> <TX_CODE>6W8010</TX_CODE> <LANGUAGE>CN</LANGUAGE> <TX_INFO> <PAY_ACCNO>转出账户号</PAY_ACCNO> <RECV_ACCNO>转入账户号</RECV_ACCNO> <RECV_ACC_NAME>转入账户名称</RECV_ACC_NAME> <CHK_RECVNAME>收款账户户名校验</CHK_RECVNAME> <RECV_OPENACC_DEPT>转入账户开户机构名称</RECV_OPENACC_DEPT> <AMOUNT>金额</AMOUNT> <CUR_TYPE>01</CUR_TYPE> <CST_PAY_NO>客户方流水号</CST_PAY_NO> <USEOF>用途</USEOF> <REM1>备注1</REM1> <REM2>备注2</REM2> </TX_INFO> <SIGN_INFO>签名信息</SIGN_INFO> <SIGNCERT>签名CA信息</SIGNCERT> </TX> </xml>'; $out = ''; if(!socket_write($socket, $in, strlen($in))) { echo "socket_write() failed: reason: " . socket_strerror($socket) . "\n"; }else { echo "发送到服务器信息成功!<br/>\n"; echo "发送的内容为:<font color='red'>$in</font> <br>"; } while($out = socket_read($socket, 8192)) { echo "接收服务器回传信息成功!<br/>\n"; echo "接受的内容为:".$out."<br/>"; } echo "关闭SOCKET...<br/>"; socket_close($socket); echo "关闭OK\n"; ?>
在看看服务端的窗口结果:
而此时服务器端代码必须一直运行,否则出错。在这方面 PHP 真的是天生的缺陷