PHP中提供了Socket扩展功能,能够很方便的实现Socket编程。在PHP手册中有两段示范代码,分别实现了TCP/IP的Server和Client。在这两个例子中,使用Socket发送或接收的都是字符串。众所周知,在PHP中有很多字符串相关的函数,处理字符串是非常方便的。但是,如果是在PHP中使用Socket函数和另一个程序通信时,不是直接用字符串来传递消息,而是用特定的数据结构比如整型甚至结构体怎么办呢?
PHP中变量的类型通常不是由程序员设定的,确切地说,是由PHP根据该变量使用的上下文在运行时决定的。PHP在变量定义中不需要(或不支持)明示的类型定义,变量类型是根据使用该变量的上下文所决定的。也就是说,如果把一个字符串值赋给变量var,var就成了一个字符串。如果又把一个整型值赋给var,那它就成了一个整数。而且PHP中的整型数的字长和平台有关(通常是32 位有符号),不支持无符号整数,那么如果要发送一个32位的无符号整数又怎么来构造它呢?
看完下面的例子,这些问题就都可以回答了。
例如要在PHP中用Socket发送或者接收一个结构体:
#define UINT8 unsigned char #define UINT32 unsigned long
typedef struct _test_struct { UINT8 type; UINT8 name[10]; UINT32 ip; } test_struct;
说明: 1. type是一个字节的无符号字符,可以取值1, 2, 3等。 2. name是一个字符串(字符数组),以’\0’结束,长度为10个字节。 3. ip是一个32位的无符号整型变量,保存IP地址。 4. 为了处理方便,假设结构体都是按1个字节对齐的(很多C编译器默认都是按4个字节对齐的),否则要根据对齐方式来计算结构体成员的偏移。
首先来看一下怎么在PHP中构造这个结构体并使用Socket发送出去。构造的结构体保存在变量$ buf中。
由于PHP中没有明确的类型定义,所以只能按字节来构造这个结构体,也就是说,只能一个字节一个字节来构造。
第一个字节是type,可以使用chr函数根据ASCII码产生一个字节的字符。例如:
$ buf = chr(1);
接着是10个字节的字符串,这个就比较容易了,直接赋值就行,但是要注意的是,如果字符串的长度不够的话,必须在后面补上’\0’来保证它是10个字节。例如:
$ name = ‘Dennis’; while (strlen($ name) < 10) { $ name .= chr(0); } $ buf .= $ name;
最后4个字节的无符号整型就比较麻烦了,要将四个字节的数拼在一起。例如:
$ ip = ‘192.168.0.1’; $ iparr = array(); $ iparr = explode('.', $ ip); $ buf .= sprintf('%c%c%c%c', $ iparr[0], $ iparr[1], $ iparr[2], $ iparr[3]);
这里用了sprintf来格式化字符串,同样也可以使用chr函数来处理。
构造完这个结构体就要通过Socket把它发送出去了,以TCP为例,发送代码如下:
// socket param $ sockip = ‘192.168.0.254’; $ sockport = 8000;
// create a udp socket $ socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($ socket < 0) { die("Socket Error!"); }
// connect to UDP port $ result = socket_connect($ socket, $ sockip, $ sockport);
if ($ result < 0) { die("Socket Error!"); }
// send data $ sent = socket_write($ socket, $ buf, strlen($ buf));
// close socket socket_close($ socket);
那么如果是接收这个结构体又怎么处理呢?可能你已经想到了,和发送类似,就是按字节去还原。下面就是具体的方法,假设Socket接受的数据保存在变量$ buf中。这里用到了和chr函数互补的另一个函数ord,它可以获得字符对应的ASCII码。
// get type $ type = ord($ buf{0});
// get name $ name = substr($ buf, 1, 10);
// get ip $ ipstr = ord($ buf{14}) . '.' . ord($ buf{13}) . '.' . ord($ buf{12}) . '.' . ord($ buf{11});
上面的代码获得的是IP地址的字符串形式,如果要获得对应的长整型,可以用下面的方法:
$ iplong = (ord($ buf{14}) << 24) + (ord($ buf{13}) << 16) + (ord($ buf{12}) << 8) + ord($ buf{11});
看到这里,上面的问题也都基本上解决了,更复杂的结构都可以通过这种“逐字节”的方法来处理。虽然之前用PHP开发比较多,但是一直没用过它来进行Socket编程,当时曾经在网上找过相关的文章,但是没有找到。上面的这种方法是我自己想出来的,也许不是最好最简单的实现方法,还是写出来,希望对大家能从中受益
|
|
随笔:279
文章:16
评论:48
引用:0
公告
留言簿(7)
随笔分类(325)
all
搜索
积分与排名
最新评论
阅读排行榜
|
|