最近在看计算机网络,对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数据发送给服务器端,并且服务器端有做了简单的处理返回给了客户端。