swoole TCP/UDP客户端

2021-05-23
use Swoole\Client;

$sock_types = [
	SWOOLE_SOCK_TCP,
	SWOOLE_SOCK_TCP6,
	SWOOLE_SOCK_UDP,
	SWOOLE_SOCK_UDP6,
	SWOOLE_KEEP, //长连接,可以与上面四个类型使用|连接使用
];
// 实例化$sock_type类型客户端,$key默认以IP:PORT作为key,相同的key多次实例化返回的时同一个tcp连接;$is_sync只有一个默认值
$client = new Client($sock_type, $is_sync = SWOOLE_SOCK_SYNC, $key);


// 设置客户端参数
$client->set([
	'socket_buffer_size' => 1024 * 1024 * 2,    // Socket缓存区尺寸,包括socket底层操作系统缓存区、应用层接收数据内存缓存区、应用层发送数据内存缓冲区。
	'open_tcp_nodelay' => true,                 //关闭Nagle合并算法
]);

// 设置客户端参数
$client->set([
	'open_eof_check' => true,    // 打开EOF检测,解决TCP数据包边界问题;开启后当数据包结尾为指定字符串时才会将数据包返回给worker进程,否则会一直拼接数据包,直到超出缓冲区或超时;当出错时底层会认为恶意连接,丢弃数据并强制关闭连接
	'package_eof' => "\r\n",     //设置EOF字符串,常见的Memcache/SMTP/POP等协议都是以\r\n结束的
]);

// 设置客户端SSL证书参数
$client->set([
	'ssl_verify_peer' => true,                  // 是否验证服务器端证书
	'ssl_allow_self_signed' => true,            // 是否允许自签名证书。
	'ssl_cert_file' => '',                      // 证书地址
    'ssl_key_file' => '',                       // 证书key地址
	'ssl_host_name' => 'www.google.com',        // 设置服务器主机名称与ssl_verify_peer配置配合使用
	'ssl_cafile' => '/etc/CA',                  // ssl_verify_peer为true时用来验证远端证书所用到的CA证书
	'ssl_capath' => '/etc/capath/',             // 证书目录,未设置ssl_cafile,或者ssl_cafile所指的文件不存在时,会在ssl_capath所指定的目录搜索适用的证书
	'ssl_passphrase' => '',                     // 本地证书ssl_cert_file文件的密码
]);


// 连接到远程服务器$host,$port;超时时间为$timeout秒;
$clients = $client->connect($host, $port, $timeout = 0.5, $flag = 0);
	// $flag 在UDP类型时表示是否启用udp_connect设定此选项后将绑定$host与$port,此UDP将会丢弃非指定host/port的数据包。

if (!$clients) {
	echo '连接错误,错误为:' . socket_strerror($client->errCode);
	// 失败重连
	// 关闭连接,$force为true表示强制关闭
	$client->close($force = true);
	$clients = $client->connect($host, $port, $timeout = 0.5, $flag = 0); 
} else {
	// 对端socket的IP地址和端口;仅支持SWOOLE_SOCK_UDP/SWOOLE_SOCK_UDP6/SWOOLE_SOCK_UNIX_DGRAM类型
	$client->getPeerName();

	// 用于获取客户端socket的本地host:port
	$client->getSockName();

    // 返回Client的连接状态,返回的是应用层状态,只表示Client执行了connect并成功连接到了Server,并且没有执行close关闭连接
	// 这不代表连接一定是可用的,执行send或recv时应用层与内核发生交互,才能得到真实的连接可用状态。
	if (!$client->isConnected()) {

	}
	// 将字符串数据$data(支持二进制)发送到服务端,返回发送数据长度;发送的数据没有长度限制,发送的数据太大Socket缓存区会塞满,程序会阻塞等待可写
	$client->send($data);

	// 发送文件$filename到服务器,sendfile不能用于UDP客户端和SSL隧道加密连接
	// $offset为文件偏移量,$length为发送数据大小,默认全部,使用$offset和$length可以从文件中间开始传输,支持断点续传
	$client->sendfile($filename, $offset = 0, $length = 0);

	// 向任意IP:PORT的主机发送UDP数据包$data,要发送的数据内容不得超过64K;client必须为udp客户端
	$client->sendto($ip, $port, $data);

	// 从服务器端接收数据,$size为接收数据的最大字节数;连接关闭将返回空字符串
	$client->recv($size = 65535, $flags = 0);

	// 从服务器端接收$size字节大小的数据,如果没有接收到$size大小将不会返回,这样可以一次性接收数据,不必循环读取
	$client->recv($size = 65535, Client::MSG_WAITALL);
}

长连接

// 实例化$sock_type类型客户端,$key默认以IP:PORT作为key,相同的key多次实例化返回的时同一个tcp连接;$is_sync只有一个默认值
$client = new Client($sock_type | SWOOLE_KEEP, $is_sync = SWOOLE_SOCK_SYNC, $key);

//表示此连接是新创建的还是复用已存在的。与SWOOLE_KEEP配合使用。 客户端与服务器建立连接后需要进行握手,如果连接是复用的,那就不需要再次进行握手,直接发送WebSocket数据帧即可。
if ($client->reuse) {
	$client->send($data);
} else {
	$client->doHandShake();
    $client->send($data);
}

 

{/if}