php中主要的socket函数语法和使用实例详解

在实际开发中,如果想要创建基于socket的应用程序,就需要详细了解socket的操作方法,要是像了解并熟练使用这些操作方法,就需要先了解php中的各种socket函数。在上一章节中我们详细介绍了php中的socket是什么?这里就介绍一下php中的socket函数。socket函数在php中有几十个之多,这里列举一些主要的socket函数来介绍一下。

它们的语法格式参数如下:

1. socket_create

socket_create ( int $domain , int $type , int $protocol )

此函数用于创建一个socket,它有三个参数,返回值是一个句柄(资源)。

$domain 指定创建socket时使用的通信协议族,其可选的值为:

AF_INET: 基于IPv4的Internet协议

AF_INET6:基于IPv6的Internet协议

AF_UNIX:UNIX本地通信协议

$type 指定socket通信的交互类型,其可选的值为:

SOCK_STREAM:提供序列化的、可靠的、全双工的、基于连接的字节流传输,支持TCP

SOCK_DGRAM:提供数据报式的、无连接的、固定最大长度的、自动寻址功能的传输,支持UDP

SOCK_SEQPACKET:提供序列化的、可靠的、双通道的、基于连接的数据报传输

SOCK_RAW:提供原始的网络访问协议,可手工构建特殊协议类型的套接字,支持ICMP请求(如 ping)

SOCK_RDM:提供可靠的数据报传输,无法保证顺序

$protocol 指定socket使用哪种具体的传输协议,包括ICMP、UDP、TCP,常量SOL_UDP对应UDP,常量SOL_TCP对应常量TCP。

2. socket_bind

socket_bind ( resource $socket , string $address [, int $port = 0 ] )

此函数用于将IP地址和端口绑定到socket_create创建的句柄中,有三个参数,返回布尔值。

$socket 是必选参数,代表socket_create函数创建的句柄

$address 是必选参数,代表要绑定的IP地址

$port 是可选参数,代表要绑定的端口号,指定哪个端口用来监听socket连接,当socket_create函数的第一个参数为AF_INET时,需要指定这个参数。

3. socket_listen

socket_listen ( resource $socket [, int $backlog = 0 ] )

该函数用于监听即将接入的socket连接,仅当socket的交互类型为SOCK_STREAM或SOCK_SEQPACKET时可

用,它有两个参数,返回布尔值。

$socket 是必选参数,代表socket_create函数创建的句柄(且已绑定了主机)

$backlog 是可选参数,表示队列中等候处理的(允许积压的)最大连接数。

4. socket_set_block

socket_set_block ( resource $socket )

该函数用于将socket句柄设置为阻塞模式,只有一个必选参数,返回布尔值。它可以将非阻塞模式的socket转换为阻塞模式。

当在一个阻塞模式的socket中执行某种操作(receive、send、connect、accept等)时,脚本将暂停执行,直到它收到一个信号或它完成了该操作。

$socket 是必选参数,代表一个有效的socket句柄(被socket_create或socket_accept创建的)。

说明一下阻塞模式非阻塞模式的区别:

非阻塞是指函数操作在不能立刻得到结果之前,不会阻塞当前的线程,而会立即返回。而阻塞是指干不完就不准回来,必须得到对方的回应后才能继续下一步操作。特别是当用户比较多时,设置成非阻塞是很必要的。如果是阻塞模式,若两个客户端同时连接上,服务器端在处理一个客户端请求时,另外一个客户端的请求就会被阻塞,只有等到前一个客户端的事情处理完了之后,后一个客户端的请求才会被响应。

5. socket_write

socket_write ( resource $socket , string $buffer [, int $length = 0 ] )

该函数用于向socket中写入指定大小的缓冲数据,有三个参数,返回写入的数据的字节数。

$socket 是必选参数,代表一个有效的socket句柄。

$buffer 是必选参数,指定要写入的字符串数据。

$length 是可选参数,指定轮流写入socket中的数据的字节数,如果它的值大于$buffer的字节数,它会静默地截取至$buffer的字节数长度。

6. socket_read

1
socket_read ( resource $socket , int $length [, int $type = PHP_BINARY_READ ] )

该函数用于从socket中读取指定字节长度的数据,有三个参数,返回读取的字符串数据。

$socket 是必选参数,代表一个有效的socket句柄。
$length 是必选参数,指定读取的字节长度。

$type 是可选参数,默认值为PHP_BINARY_READ,即安全读取二进制数据;另一个可选的值为PHP_NORMAL_READ,表示当遇到 \r 或 \n 时,停止读取。

7. pfsockopen

1
pfsockopen ( string $hostname [, int $port = -1 [, int &$errno [, string &$errstr [, float $timeout = ini_get("default_socket_timeout") ]]]] )

该函数用于实现一个持久的socket连接,即长连接,返回一个句柄。它与 fsockopen 的区别在于,pfsockopen 建立的连接,在脚本执行完毕后,并不会断开。

8. socket_set_option

1
socket_set_option ( resource$socket , int$level , int$optname , mixed$optval )

该函数用于设置socket的控制选项,有四个参数,返回布尔值。

$socket 是必选参数,代表一个有效的socket句柄。

$level 是必选参数,指定option起作用的协议级别,一般取常量 SOL_SOCKET。

$optname 是必选参数,指定要控制的选项名称。

$optval 是必选参数,指定选项的值。

9. socket_last_error

1
socket_last_error ([ resource$socket ] )

该函数用于获取任何socket函数产生的最后错误代号,返回值为整型。

10. socket_strerror

1
socket_strerror ( int $errno )

该函数用于获取错误代号代表的错误描述,返回值为字符串。

以上所有的函数都是PHP中关于socket的,使用这些函数,你必须把你的socket打开,如果你没有打开,请编辑你的php.ini文件,去掉下面这行前面的注释:

1
extension=php_sockets.dll

如果你不知道你的socket是否打开,那么你可以使用phpinfo()函数来确定socket是否打开。

下面通过创建一个服务端和客户端的例子来说明这些函数的用法:

  1. 服务器端
</div>
<div class="line number1 index0 alt2"><code class="php plain"><?php</code></div>
<div class="line number2 index1 alt1"><code class="php comments">//确保在连接客户端时不会超时</code></div>
<div class="line number3 index2 alt2"><code class="php plain">set_time_limit(0);</code></div>
<div class="line number4 index3 alt1"><code class="php variable">$ip</code> <code class="php plain">= </code><code class="php string">'127.0.0.1'</code><code class="php plain">;</code></div>
<div class="line number5 index4 alt2"><code class="php variable">$port</code> <code class="php plain">= 1935;</code></div>
<div class="line number6 index5 alt1"><code class="php comments">/*</code></div>
<div class="line number7 index6 alt2"><code class="php spaces"> </code><code class="php comments">+-------------------------------</code></div>
<div class="line number8 index7 alt1"><code class="php spaces"> </code><code class="php comments">*    @socket通信整个过程</code></div>
<div class="line number9 index8 alt2"><code class="php spaces"> </code><code class="php comments">+-------------------------------</code></div>
<div class="line number10 index9 alt1"><code class="php spaces"> </code><code class="php comments">*    @socket_create</code></div>
<div class="line number11 index10 alt2"><code class="php spaces"> </code><code class="php comments">*    @socket_bind</code></div>
<div class="line number12 index11 alt1"><code class="php spaces"> </code><code class="php comments">*    @socket_listen</code></div>
<div class="line number13 index12 alt2"><code class="php spaces"> </code><code class="php comments">*    @socket_accept</code></div>
<div class="line number14 index13 alt1"><code class="php spaces"> </code><code class="php comments">*    @socket_read</code></div>
<div class="line number15 index14 alt2"><code class="php spaces"> </code><code class="php comments">*    @socket_write</code></div>
<div class="line number16 index15 alt1"><code class="php spaces"> </code><code class="php comments">*    @socket_close</code></div>
<div class="line number17 index16 alt2"><code class="php spaces"> </code><code class="php comments">+--------------------------------</code></div>
<div class="line number18 index17 alt1"><code class="php spaces"> </code><code class="php comments">*/</code></div>
<div class="line number19 index18 alt2"><code class="php comments">/*----------------    以下操作都是手册上的    -------------------*/</code></div>
<div class="line number20 index19 alt1"><code class="php keyword">if</code><code class="php plain">((</code><code class="php variable">$sock</code> <code class="php plain">= socket_create(AF_INET,SOCK_STREAM,SOL_TCP)) < 0) {</code></div>
<div class="line number21 index20 alt2"><code class="php spaces">    </code><code class="php functions">echo</code> <code class="php string">"socket_create() 失败的原因是:"</code><code class="php plain">.socket_strerror(</code><code class="php variable">$sock</code><code class="php plain">).</code><code class="php string">"\n"</code><code class="php plain">;</code></div>
<div class="line number22 index21 alt1"><code class="php plain">}</code></div>
<div class="line number23 index22 alt2"><code class="php keyword">if</code><code class="php plain">((</code><code class="php variable">$ret</code> <code class="php plain">= socket_bind(</code><code class="php variable">$sock</code><code class="php plain">,</code><code class="php variable">$ip</code><code class="php plain">,</code><code class="php variable">$port</code><code class="php plain">)) < 0) {</code></div>
<div class="line number24 index23 alt1"><code class="php spaces">    </code><code class="php functions">echo</code> <code class="php string">"socket_bind() 失败的原因是:"</code><code class="php plain">.socket_strerror(</code><code class="php variable">$ret</code><code class="php plain">).</code><code class="php string">"\n"</code><code class="php plain">;</code></div>
<div class="line number25 index24 alt2"><code class="php plain">}</code></div>
<div class="line number26 index25 alt1"><code class="php keyword">if</code><code class="php plain">((</code><code class="php variable">$ret</code> <code class="php plain">= socket_listen(</code><code class="php variable">$sock</code><code class="php plain">,4)) < 0) {</code></div>
<div class="line number27 index26 alt2"><code class="php spaces">    </code><code class="php functions">echo</code> <code class="php string">"socket_listen() 失败的原因是:"</code><code class="php plain">.socket_strerror(</code><code class="php variable">$ret</code><code class="php plain">).</code><code class="php string">"\n"</code><code class="php plain">;</code></div>
<div class="line number28 index27 alt1"><code class="php plain">}</code></div>
<div class="line number29 index28 alt2"><code class="php variable">$count</code> <code class="php plain">= 0;</code></div>
<div class="line number30 index29 alt1"><code class="php keyword">do</code> <code class="php plain">{</code></div>
<div class="line number31 index30 alt2"><code class="php spaces">    </code><code class="php keyword">if</code> <code class="php plain">((</code><code class="php variable">$msgsock</code> <code class="php plain">= socket_accept(</code><code class="php variable">$sock</code><code class="php plain">)) < 0) {</code></div>
<div class="line number32 index31 alt1"><code class="php spaces">        </code><code class="php functions">echo</code> <code class="php string">"socket_accept() failed: reason: "</code> <code class="php plain">. socket_strerror(</code><code class="php variable">$msgsock</code><code class="php plain">) . </code><code class="php string">"\n"</code><code class="php plain">;</code></div>
<div class="line number33 index32 alt2"><code class="php spaces">        </code><code class="php keyword">break</code><code class="php plain">;</code></div>
<div class="line number34 index33 alt1"><code class="php spaces">    </code><code class="php plain">} </code><code class="php keyword">else</code> <code class="php plain">{</code></div>
<div class="line number35 index34 alt2"><code class="php spaces">        </code></div>
<div class="line number36 index35 alt1"><code class="php spaces">        </code><code class="php comments">//发到客户端</code></div>
<div class="line number37 index36 alt2"><code class="php spaces">        </code><code class="php variable">$msg</code> <code class="php plain">=</code><code class="php string">"测试成功!\n"</code><code class="php plain">;</code></div>
<div class="line number38 index37 alt1"><code class="php spaces">        </code><code class="php plain">socket_write(</code><code class="php variable">$msgsock</code><code class="php plain">, </code><code class="php variable">$msg</code><code class="php plain">, </code><code class="php functions">strlen</code><code class="php plain">(</code><code class="php variable">$msg</code><code class="php plain">));</code></div>
<div class="line number39 index38 alt2"><code class="php spaces">        </code></div>
<div class="line number40 index39 alt1"><code class="php spaces">        </code><code class="php functions">echo</code> <code class="php string">"测试成功了啊\n"</code><code class="php plain">;</code></div>
<div class="line number41 index40 alt2"><code class="php spaces">        </code><code class="php variable">$buf</code> <code class="php plain">= socket_read(</code><code class="php variable">$msgsock</code><code class="php plain">,8192);</code></div>
<div class="line number42 index41 alt1"><code class="php spaces">        </code></div>
<div class="line number43 index42 alt2"><code class="php spaces">        </code></div>
<div class="line number44 index43 alt1"><code class="php spaces">        </code><code class="php variable">$talkback</code> <code class="php plain">= </code><code class="php string">"收到的信息:$buf\n"</code><code class="php plain">;</code></div>
<div class="line number45 index44 alt2"><code class="php spaces">        </code><code class="php functions">echo</code> <code class="php variable">$talkback</code><code class="php plain">;</code></div>
<div class="line number46 index45 alt1"><code class="php spaces">        </code></div>
<div class="line number47 index46 alt2"><code class="php spaces">        </code><code class="php keyword">if</code><code class="php plain">(++</code><code class="php variable">$count</code> <code class="php plain">>= 5){</code></div>
<div class="line number48 index47 alt1"><code class="php spaces">            </code><code class="php keyword">break</code><code class="php plain">;</code></div>
<div class="line number49 index48 alt2"><code class="php spaces">        </code><code class="php plain">};</code></div>
<div class="line number50 index49 alt1"><code class="php spaces">        </code></div>
<div class="line number51 index50 alt2"><code class="php spaces">    </code></div>
<div class="line number52 index51 alt1"><code class="php spaces">    </code><code class="php plain">}</code></div>
<div class="line number53 index52 alt2"><code class="php spaces">    </code><code class="php comments">//echo $buf;</code></div>
<div class="line number54 index53 alt1"><code class="php spaces">    </code><code class="php plain">socket_close(</code><code class="php variable">$msgsock</code><code class="php plain">);</code></div>
<div class="line number55 index54 alt2"><code class="php plain">} </code><code class="php keyword">while</code> <code class="php plain">(true);</code></div>
<div class="line number56 index55 alt1"><code class="php plain">socket_close(</code><code class="php variable">$sock</code><code class="php plain">);</code></div>
<div class="line number57 index56 alt2"><code class="php plain">?></code></div>
<div>
<?php
error_reporting(E_ALL);
set_time_limit(0);
echo "<h2>TCP/IP Connection</h2>\n";
$port = 1935;
$ip = "127.0.0.1";
/*
 +-------------------------------
 *    @socket连接整个过程
 +-------------------------------
 *    @socket_create
 *    @socket_connect
 *    @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.\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\n";
}
$in = "Ho\r\n";
$in .= "first blood\r\n";
$out = '';
if(!socket_write($socket, $in, strlen($in))) {
    echo "socket_write() failed: reason: " . socket_strerror($socket) . "\n";
}else {
    echo "发送到服务器信息成功!\n";
    echo "发送的内容为:<font color='red'>$in</font> <br>";
}
while($out = socket_read($socket, 8192)) {
    echo "接收服务器回传信息成功!\n";
    echo "接受的内容为:",$out;
}
echo "关闭SOCKET...\n";
socket_close($socket);
echo "关闭OK\n";
?>