目录
#常用调试方式总结
ctrl+z 不能杀死进程只是调到了后台,ctrl+c才会直接杀死进程
kill -9 进程号 杀死进程
netstat -pantu | grep 端口号 查询套接字
#Socket
socket_create ( int $domain
, int $type
, int $protocol
) : resource
$errcode = socket_last_error() 获取错误码
$errmsg = socket_strerror($errcode) 根据错误码获取错误信息
$address 用于指定 可以连接该套接字的IP地址 例如 127.0.0.1 表示只有本机可以连接该套接字
$address = '0.0.0.0' 表示所有的内网主机都可以和该套接字连接
$address = 0 表示所有的外网 和 内网 主机 都可以 和该套接字连接
#一个最基础的demo:
服务端:
<?php
$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
$error_code = socket_last_error();
$error_msg = socket_strerror($error_code);
$addr ='0.0.0.0';
$port = 666666;
socket_bind($socket,$addr,$port);
socket_listen($socket);
//等待客户端连接
$conn_sock = socket_accept($socket);
$str = "this data is from server";
//向客户端发送数据
socket_write($conn_sock,$str,strlen($str));
//接收客户端发送的数据
$data = socket_read($conn_sock,1024);
var_dump($data);
socket_close($socket);
客户端:
$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
$res = socket_connect($socket,'127.0.0.1',666666);
//接受服务端的数据
$str = socket_read($socket,1024);
//向服务端发送数据
socket_write($socket,'this data is from client');
var_dump($str);
socket_close($socket);
这里有一点需要注意一下:
如果客户端调用了socket_close 而服务端却没有调用
就相当于客户端向服务端发送了FIN,因为服务端没有调用socket_close ,所以服务端只能被动发送FIN 三次挥手,
这时会导致 服务端的套接字 处于CLOSE_WAIT状态,一直占用端口。
解决方法:https://blog.csdn.net/microgp/article/details/86588973
#一个更复杂的DEMO
客户端:
$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
socket_connect($socket,'101.200.142.148',6666);
while(true){
//终端输出
fwrite(STDOUT,'请输入内容:');
//终端输入
$in = fgets(STDIN);
socket_write($socket,$in,strlen($in));
echo socket_read($socket,1024);
}
服务端:
<?php
$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
$error_code = socket_last_error();
$error_msg = socket_strerror($error_code);
$addr ='0';
$port = 6666;
//让套接字端口被释放后可以立即被使用
socket_set_option($socket,SOL_SOCKET,SO_REUSEADDR,true);
socket_bind($socket,$addr,$port);
socket_listen($socket);
while(true){
$conn_sock = socket_accept($socket);
socket_getpeername($conn_sock,$ip,$port);
echo 'ip:'.$ip.'...port:'.$port.'...connected'.PHP_EOL;
while(true){
$data = socket_read($conn_sock,1024);
echo $data;
$recv = fgets(STDIN);
socket_write($conn_sock,$recv,strlen($recv));
}
}
#io多路复用
实现IO多路复用有两种模型:select 模型 和epoll模型
demo:
<?php
$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
$error_code = socket_last_error();
$error_msg = socket_strerror($error_code);
$addr ='0';
$port = 6666;
socket_set_option($socket,SOL_SOCKET,SO_REUSEADDR,true);
socket_bind($socket,$addr,$port);
socket_listen($socket);
$sockets[] = $socket;
$write = null;
$except = null;
while(true){
$tmp_sockets = $sockets;
var_dump($tmp_sockets);
var_dump($sockets);
socket_select($tmp_sockets,$write,$except,null);
echo "socket_select的返回值";
var_dump($tmp_sockets);
foreach($tmp_sockets as $sock){
if($sock == $socket){
$conn_sock = socket_accept($socket);
socket_getpeername($conn_sock,$ip,$port);
echo 'ip:'.$ip.'...port:'.$port.'...connected'.PHP_EOL;
$sockets[] = $conn_sock;
var_dump($sockets);
}else{
$data = socket_read($sock,1024);
echo $data;
}
}
}
$read 数组传入socket_select后
socket_select 正如其名,会选择当前活跃的 socket 作为 $read数组的元素(因为传入的是$read的地址,所以$read可以被修改)
例如可以将 socket 和 conn_socket 组成 $read数组 传给 socket_select
如果是建立连接,socket 处于活跃状态 被返回
如果是传输数据,conn_socket 处于活跃状态被返回
以上是一个客户端 和一个服务端 通信时 $read的组成
如果有多个客户端 和服务端通信 $read = [ $socket,$conn_socket1,$conn_socket2 ....]
#一个简易web服务器
$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
$error_code = socket_last_error();
$error_msg = socket_strerror($error_code);
$addr ='0';
$port = 6666;
socket_set_option($socket,SOL_SOCKET,SO_REUSEADDR,true);
socket_bind($socket,$addr,$port);
socket_listen($socket);
$sockets[] = $socket;
$write = null;
$except = null;
while(true){
$tmp_sockets = $sockets;
socket_select($tmp_sockets,$write,$except,null);
foreach($tmp_sockets as $sock){
if($sock == $socket){
$conn_sock = socket_accept($socket);
socket_getpeername($conn_sock,$ip,$port);
$sockets[] = $conn_sock;
}else{
$content = "<h1>Hello DataBank!</h1>";
$content_len = strlen($content);
$response = "HTTP/1.1 200 OK\r\n";
$response .= "Content-Type:text/html;charset=utf-8\r\n";
//$response .= "Content-Length:".$content_len."\r\n\r\n";
$response .= $content;
@socket_write($sock,$response,strlen($response));
}
}
}