PHP Socket库

目录

#常用调试方式总结

#Socket

#一个最基础的demo:

#一个更复杂的DEMO

#io多路复用

#一个简易web服务器


#常用调试方式总结

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));
		}
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值