/首页
/开源
/关于
PHP网络编程-socket基础篇(九)
发表@2020-01-05 18:19:00
更新@2023-03-27 17:33:15
大家好,我是嗓音你从未听过、相貌你们尚未见过、随手一编就能瞎编文章一坨的老李。  今天接着昨天的socket_recv()继续编,上来就得先尝试解决一个问题:客户端每次发来的数据长度都是不固定的,怎么办? - 你问:“ 啊?我哪儿知道怎么办?老李,难不成你今天这篇文章要说这个? ” - 我答:“ 是啊,是啊 ” - 你问:“ 啊,这都被我猜到了! ” - 我答:“ 是啊是啊,不然这TM文章我都不知道该这么继续编下去了 ” - 你问:“ 哎呀呀呀,哪儿你这样写文章的,编不下去强行编 ” - 我答:  其实每次数据长度不固定就是原本的网络世界,每次发送数据长度都一样才叫诡异。一般说来,这个问题有两种解决方案: - header+body:其中header里只有一个长度,这个长度就是后面body体的长度。当读取了header里存储的body长度后,就可以指定socket_recv()里的length了。 - EOF:这种比较粗暴,约定数据分界线的分界标识符,比如\r\n,也就是说服务器收到数据后一旦遇到\r\n就算到头;这里处理上的细节就是使用while循环调用socket_recv(),一直读到有\r\n 我琢磨了一下,决定采用第一种,主要是第二种写demo代码比较恶心而我又比较懒。在正式开始前,我要介绍一对函数,这对函数可能有人接触过,而且还对着文档研究过,但是研究后又发现似乎完全看不懂文档在说什么;然后我还要再介绍一对概念: - pack()/unpack() - 网络字节序/主机字节序 先说下网络字节序和主机字节序,这两个词英文分别叫做big-endian/little-endian,所以有些地方翻译过来又分别叫大端字节序和小端字节序。据说啊,从这计算机出生的时候,用的就是主机字节序(小端字节序)大概意思就是电路优先从低位开始读取数据效率贼高,谁知道后来有了网,这网上的数据都是网络字节序。这两个玩意的历史大概就是这样的。 比如说0x12345678这个数字(十六进制),高位其实就是1,最低位是8,其实就是百分位,比如说[ 178元 ]中1所在位置是百位、7是十位、8是个位。假如说内存地址从0x0001开始一直到0x0004(从低内存到高内存),那么我们下面分别按照网络字节序和主机字节序在内存中存储应该是什么样的。 这个数字按照网络字节序在内存里排列,就是这样的,也就是高位字节放在了低内存处: ```php 0x0004 78 0x0003 56 0x0002 34 0x0001 12 ``` 按照主机字节序在内存排列,那就是这样的,也就是说高位字节放在高内存处: ```php 0x0004 12 0x0003 34 0x0002 56 0x0001 78 ``` 到这里事情就清楚了,如果说从网上飞来一坨数据钻到主机的内存里后,CPU如果要读出来就一定会存在字节序的问题了,也就是字节序是需要转换的。可惜在PHP里对字节序转换可能并不多,如果看UNP或者APUE的话,里面有大量函数提供主机/网络字节序转换功能,我举几个例子: ```php htons()/ntohs() 分别是将主机字节序转为网络字节序、将网络字节序转为主机字节序 这个可以满足short类型数值 htonl()/ntohl() 分别是将主机字节序转为网络字节序、将网络字节序转为主机字节序 这个可以满足long类型数值 inet_ntoa()/inet_aton() 这个是将IP地址按照规则进行转换的函数 ``` 在PHP里,如果你想要按照某种字节序飞数据,那么pack()函数就可以帮你满足愿望,当然了负责接受数据的地方自然要用unpack()来处理应对咯。 UNP和APUE这么恶心,所以你们是不是感觉用PHP很幸福呢?大声告诉我用PHP香不香?  好了,代码我写好了,你们复制粘贴一下跑跑看看能不能用。
服务器
```php 客户端
```php