先扯蛋
本来有点想删掉了【一直在草稿里呆好久了,想想还是发布吧,兴许可能有人用得上】
laravel里的系列文章功能用得不顺手,不知道咋搞的,我就直接粗暴的粘链接了。时间原因,本来是想再深入的,想想有机会再补充吧。
PHP socket 手册
使用需求
系统平台
php -m 或 php --ri sockets
显示如上,表示php已经支持socket扩展
几行代码先运行
$ip = "0.0.0.0";
$port = $argv[1];
$sockefd = socket_create(AF_INET,SOCK_STREAM,0);
echo $sockefd.PHP_EOL;
$pid = posix_getpid();
echo "pid=".$pid.PHP_EOL;
echo `ls -al /proc/{$pid}/fd`;//为了方便看该进程生成的数据
socket_bind($sockefd,$ip,$port);
socket_listen($sockefd,5);
while (1){}
然后我php socket1.php 12345
结果显示如下
我先来解释先
Resource id #4那是PHP返回的,在PHP里称为资源
0它是一个字符输入设备也是文件描述符【linux皆文件】
1它是一个字符输出设备也是文件描述符
2同样的也是
3比较特殊它是一个epoll类型的文件,链接着一个匿名节点
4是一个socket类型的文件,它的结点是9460457
5是一个管道文件
实际上我去对应的目录看是没有这文件的,可以先不理它
在linux上它是这样的
接下来我们继续看socket:[9460457]->4
先看它的网络状态,我们cat net/tcp即可
先对几个重要的选项解释一下
local_address表示本地ip和端口号用16进制表示
rem_address 远程服务器ip和端口
st 表示套接字状态
1 TCP_ESTABLISHED
2 TCP_SYN_SENT
3 TCP_SYN_RECV
4 TCP_FIN_WAIT1
5 TCP_FIN_WAIT2
6 TCP_TIME_WAIT
7 TCP_CLOSE
8 TCP_CLOSE_WAIT
9 TCP_LAST_ACK
10 TCP_LISTEN 16进制就是A
11 TCP_CLOSING
tx_queue 发送队列中的数据长度
rx_queue 接收的数据长度
tr 定时器类型
0未启动定时
1开启socket 定时重传机制
4开启持续定时
2开启连接定时器 FIN_WAIT2定时
3 TIME_WAIT定时
tm->when 超时时间
retrnsmt 超时重传次数
uid 用户的id
inode socket套接字对应的结点inode
大家都了解TCP数据流拥有自己的接收缓冲区和发送缓冲区,同时呢具有超时重传机制和数据应答确诊机制
这个socket它的状态用netstat -antp查看就是这样的
所以我们socket_create后它创建了一个TCP并且处于监听状态中即LISTEN。
我们在代码的最后一句加上了while就是让它一直循环在那运行R(running),我们在该进程生成的目录下可以查看
发起一个网络连接一下看看效果
在发起连接之前我们先要执行tcpdump -i lo port 12345
然后使用telnet工具去连接,得到的结果如下
22:33:44.827309 IP localhost.37510 > localhost.italk: Flags [S], seq 1537400892
01:50:55.605018 IP localhost.italk > localhost.37510: Flags [S.], seq 1228325870, ack 1537400893
22:33:44.827328 IP localhost.37510 > localhost.italk: Flags [.], ack 1
前面的是时间,localhost.37510是客户端的ip和系统分配的随机端口
而localhost.italk是本机
Flags
- SYN 表示发起一个连接
- ACK 一个应答
- RST 重新发起连接
- PSH 在传输数据时会有这个标志位
- URG 紧急标志位
- FIN 一个关闭报文
seq 表示源IP向目标IP传输的序列号
对端应答的时候必须在其基础上加1操作
ack 表示确认序列号,一般在seq上加1进行应答确认
以上的内容完成了大家比较熟悉的TCP连接三次握手
我想知道细节,想知道它到底在干嘛
下面我来添加几句代码,我们来更清楚的知道它们是怎么玩在一起的,是怎么进行通信的
....
while (1){
$connfd = socket_accept($sockefd);
echo $connfd.PHP_EOL;
socket_write($connfd,"hello,php 是世界上是好的语言");
}
然后输入如下命令
strace -f php socket1.php 12345
抽核心大概流程
- exec
- read socket1.php
- create socket
- exec sh
- bind,listen,accept
就大概这么几句,创建socket返回文件描述符4,然后bind绑定,监听,最后呢在accept函数阻塞进程【Sleeping状态】cpu已经做其它事情了,毕竟它在”睡觉中”
接下来我们同样用telnet工具来连接并传输数据
接下来我们再加几句代码让其它成基本的响应给客户端
while (1){
$connfd = socket_accept($sockefd);
echo $connfd.PHP_EOL;
socket_write($connfd,"hello,php 是世界上是好的语言");
echo socket_read($connfd,4098,PHP_BINARY_READ);
}
我们看到php语言低层调用了c函数【任何语言都是一样】
都是先创建一个socketfd,再把端口和地址绑架到它身上,再listen进行监听,直到accept阻塞,有客户端连接时才会唤醒该进程来处理数据。所以务必动手实验才能领略阻塞和唤醒的感觉。
文章评论
ggg