最近在看计算机网络,对socket原语有了一个新的认识,发现php也可以支持socket编程,而且非常方便。大家可以查看php手册,里面有很全面的socket操作函数。
然后我就写了一个简单的实例,大家可以借鉴一下。
首先说明一下,如果大家对socket不是很了解的话,那么先补充一下socket的知识。
socket可以直接和传输层的tcp协议交互,然后实现端对端的数据传输,socket的存在其实是一对,服务器端对客户端。
所以我们要实现的代码也是首先要实现服务器端,然后再实现客户端,先启动服务器端,以一个进程的形式在等待客户端调用,一旦客服端发起连接请求,服务器端就会和客户端创建一个连接,然后开始和客户端进行数据传输。
原语 | 含义 |
SOCKET | 创建一个新的通讯端点 |
BIND | 将套接字与一个本地地址关联 |
LISTEN | 声明愿意接受连接;给出队列长度 |
ACCEPT | 被动创建一个入境连接 |
CONNECT | 主动创建一个连接 |
SEND | 通过连接发送一些数据 |
RECEIVE | 从连接上接收一些数据 |
CLOSE | 释放链接 |
#!/usr/bin/php -q <?php require './socket.php'; $error_code = socket_server();
客户端代码:client.php
<?php require './socket.php'; $server_ip = LOCALHOST_IP; $socket_port = DEFAULT_SOCKET_PORT; $data = 'hello world!'; socket_client($server_ip, $socket_port, $data);公用脚本(这里面是对服务器端和客户端具体实现): socket.php
<?php set_time_limit(0); define('LOCALHOST_IP', '127.0.0.1'); define('DEFAULT_SOCKET_PORT', 2407); //允许同时连接到服务器端的客户机数目 define('MAX_CONNECT_NUM', 5); define('DATA_LENGTH', 1024); //定义服务器端错误code define('SOCKET_CREATE_ERROR', '44001'); define('SOCKET_SETBLOCK_ERROR', '44002'); define('SOCKET_BIND_ERROR', '44003'); define('SOCKET_LISTEN_ERROR', '44004'); define('SOCKET_ACCEPT_ERROR', '44005'); define('SOCKET_READ_DATA_ERROR', '44005'); define('SOCKET_WRITE_ERROR', '44006'); //定义客户端错误code define('SOCKET_CLIENT_CREATE_FAILED', '55001'); define('SOCKET_CLIENT_CONNECT_FAILED', '55002'); define('SOCKET_CLIENT_WRTIE_ERROR', '55003'); /** * 启用socket服务器端方法 * @param:$host string 服务器端地址 default localhost * @param:$port int 服务器端口地址 default 2406 * @param:$block bool 设置阻塞模式,true:阻塞 false:非阻塞 default true * @param:$error string 错误信息 */ function socket_server($host = LOCALHOST_IP, $port = DEFAULT_SOCKET_PORT, $block = true, $max_connect = MAX_CONNECT_NUM, &$error = '') { //创建一个soket通讯端点 if ( !($socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) ) { $error = "socket端点创建失败:" . get_socket_last_err(); return SOCKET_CREATE_ERROR; } if ( $block ) $block_ret = socket_set_block($socket); else $block_ret = socket_set_nonblock($socket); if ( !$block_ret ) { $error = '阻塞模式设置失败:' . get_socket_last_err(); return SOCKET_SETBLOCK_ERROR; } //将套接字和服务器地址绑定 if ( !socket_bind($socket, $host, $port) ) { $error = "绑定服务器地址失败:" . get_socket_last_err(); return SOCKET_BIND_ERROR; } //声明自己愿意接受连接,给出队列长度,同时可以允许多少个客户端连接到服务器 if ( !socket_listen($socket, $max_connect) ) { $error = "服务器监听失败" . get_socket_last_err(); return SOCKET_LISTEN_ERROR; } $curr_buff = ''; $client_id = 0; while ( true ) { //被动创建一个入境连接 if ( !($msg_socket = socket_accept($socket)) ) { $error = "创建入境连接失败" . get_socket_last_err(); return SOCKET_ACCEPT_ERROR; } //从连接开始接收数据 $buf = socket_read($msg_socket, DATA_LENGTH, PHP_BINARY_READ); if ( false === $buf ) { $error = "读取数据失败" . get_socket_last_err(); return SOCKET_READ_DATA_ERROR; } $client_id ++; if ( $buf == "\r\n" ) { if ( $curr_buff == 'quit' ) { $error = "Client #" . $client_id . ":Disconnect\n"; } if ( $curr_buff == 'shutdown' ) { socket_close($msg_socket); } } $msg = "Received msg was:$buf \n"; //error_log(date("Y-m-d H:i:s") . "\t" . $msg, 3, "/tmp/log"); if ( !socket_write($msg_socket, $msg, strlen($msg)) ) { $error = "write failed reason:" . get_socket_last_err(); return SOCKET_WRITE_ERROR; } socket_close($msg_socket); } } /** * socket客户端方法 * @param:$host string 服务器端地址 default localhost * @param:$port int 服务器端口地址 default 2406 * @param:$data mixed 要发送给服务器端的数据 * @param:$error string 错误信息 */ function socket_client($host = LOCALHOST_IP, $port = DEFAULT_SOCKET_PORT, $data = '', &$error = '') { //创建客户端socket通讯端点 if ( !($socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) ) { $error = "socket端点创建失败:" . get_socket_last_err(); return SOCKET_CLIENT_CREATE_FAILED; } if ( !socket_connect($socket, LOCALHOST_IP, DEFAULT_SOCKET_PORT) ) { $error = "连接socket服务器失败:" . get_socket_last_err(); return SOCKET_CLIENT_CONNECT_FAILED; } if ( !socket_write($socket, $data) ) { $error = "数据发送失败" . get_socket_last_err(); return SOCKET_CLIENT_WRTIE_ERROR; } while ($buff = @socket_read($socket, DATA_LENGTH, PHP_NORMAL_READ) ) { echo ("Respones was:" . $buff . "\n"); } socket_close($socket); } /** * 获取socket执行的最后一条错误 */ function get_socket_last_err() { $error = socket_strerror(socket_last_error()) . "\n"; }把三个文件放到相同的目录下,然后php cli方式运行server.php以进程的方式挂载起来:php server.php &之后就可以运行client.php,也用cli方式运行:php client.php就可以看到hello world!,这说明客户端已经把data数据发送给服务器端,并且服务器端有做了简单的处理返回给了客户端。