当前位置: 首页 > news >正文

PHP Swoole Client

PHP常用socket创建TCP连接,使用CURL创建HTTP连接,为了简化操作,Swoole提供了Client类用于实现客户端功能,并增加了异步非阻塞模式,让用户在客户端也能使用事件循环。

作为客户端使用,Swoole Client可以在FPM环境下或 Apache中使用,但不允许使用Async异步模式,只能使用同步非阻塞模式,异步非阻塞模式仅限CLI模式下使用。

Client提供了TCP/UDP socket的客户端的封装代码,使用时仅需new Swoole\Client。

Swoole的socket客户端对比PHP提供的stream族函数有什么优势呢?

stream函数存在超时设置的陷阱和Bug,一旦没有处理好将会导致服务器长时间阻塞。
stream和fread有8192长度限制,无法支持UDP大包。
swoole_client客户端支持waitall,在知道包长度的情况下可以一次取完不必循环获取。
swoole_client支持UDP的connect解决了UDP串包的问题
swoole_client是纯C的代码
swoole_client支持异步非阻塞回调
构造方法 constructor
Swoole的Client功能封装为一个swoole_client类,可通过new swoole_client来创建一个客户端实例。

原型
 

swoole_client->__construct(int $sock_type, int $is_async = SWOOLEL_SOCK_SYNC, string $key
);

参数
参数1:int $sock_type
$sock_type 表示socket类型,可使用swoole提供的宏来指定类型。

  • SWOOLE_TCP 创建TCP Socket
  • SWOOLE_TCP6 创建IPv6 TCP Socket
  • SWOOLE_UDP 创建UDP Socket
  • SWOOLE_UDP6 创建IPv6 UDP Socket
  • SWOOLE_SSL 开启SSL加密
  • SWOOLE_KEEP 开启连接复用

其中SWOOLE_SSL与SWOOLE_KEEP不能单独使用,需要与前四个选项共同作用。
 

// 创建并开启SSL加密的TCP客户端
$client = new swoole_client(SWOOLE_TCP | SWOOLE_SSL);

SWOOLE_KEEP

swoole_client支持在PHP-FPM或Apache中建立一个TCP长连接到服务器,当客户端启用SWOOLE_KEEP选项后,一个请求结束不会关闭socket,下一次再进行connect连接时会自动复用上次创建的连接。如果执行connect连接时发现连接已经 被服务器断开,那么connect将会创建新的连接。

// 创建一个可以在FPM中使用的长连接客户端

$client = new swoole_client(SWOOLE_TCP | SWOOLE_KEEP);


SWOOLE_KEEP建立TCP长连接有什么优势呢?

TCP长连接可以减少connect建立连接时的三次握手和close断开连接的四次挥手所带来的额外IO开销
降低服务器connect建立连接和close断开连接的次数
例如:在PHP-FPM模式下可以使用同步模式的swoole_client向后端发送数据,为了能够让不同的连接复用同一个客户端client,可以开启SWOOLE_KEEP选项并指定对应的key。这样对于同一个逻辑就不需要为每个请求都创建一个新的连接了。这里需要注意的是,虽然共用了同一个连接,但是每个请求仍然会创建一个新的swoole_client实例,只是这些实例底层会复用同一个TCP连接。因此,如果开启了SWOOLE_KEEP选项也就不能随便调用close关闭客户端,并且在使用时可使用isConnect方法来判断连接是否可用。

<?php
//获取参数
$data = isset($_GET["data"])&&!empty($_GET["data"]) ? $_GET["data"] : "";
//创建同步阻塞TCP客户端,并开启连接复用。
$host = "127.0.0.1";
$port = 9501;
$key = $host.":".$port;//默认使用IP:PORT作为长连接的key,具有相同key的连接会被复用。
$client = new swoole_client(SWOOLE_TCP | SWOOLE_KEEP, SWOOLE_SYNC, $key);
//判断客户端时已连接
if(!$client->isConnect()){$client->connect($host, $port);
}
//发送数据
$client->send($data);
//接收打印
echo $client->recv();


参数2:int $is_sync
$is_sync表示同步阻塞或异步非阻塞,默认为同步阻塞。模式不同决定了可以使用的API的不同。

SWOOLE_SOCK_SYNC

SWOOLE_SOCK_SYNC 表示创建一个同步阻塞客户端,默认设置。

swoole_client(SWOOLE_TCP, SWOOLE_SYNC, $key);


当设定swoole_client为同步模式后,可以像使用PHP的sockets扩展也一样使用swoole_client来创建socket连接。由于是同步阻塞模式,所以connect、recv、send这样的方法都会阻塞进程。相比较PHP的sockets扩展提供的方法,swoole_client的API更为简洁,使用起来更加方便。

<?php
/*** 创建同步阻塞模式下的TCP客户端* 同步阻塞模式下connect/send/recv会等待IO完成后再返回,服务端返回后才会向下执行。* 同步阻塞模式下并不会消耗CPU资源,IO操作未完成当前进程会自动转入sleep模式。* 当IO完成后操作系统会唤醒当前进程,继续向下执行代码。* */
$client = new swoole_client(SWOOLE_TCP);//连接到服务器
$host = "127.0.0.1";
$port = 9501;
$timeout = 1;//超过与服务器交互的超时秒数会自动断开
if(!$client->connect($host, $port, $timeout)){die("[connect] failed".PHP_EOL);
}//发送数据
$message = "hello world";
if(!$client->send($message)){die("[send] failed".PHP_EOL);
}//接收数据
if(!$data = $client->recv()){die("[recv] failed".PHP_EOL);
}
echo $data.PHP_EOL;//关闭连接
$client->close();


SWOOLE_SOCK_ASYNC

SWOOLE_SOCK_ASYNC 表示创建一个异步非阻塞客户端

需要通过on方法注册异步回调函数
多个swoole_client客户端可以嵌套回调
异步模式仅可用于CLI命令行模式

swoole_client(SWOOLE_TCP, SWOOLE_SOCK_ASYNC)


当设置swoole_client为异步模式后,swoole_client就不能再使用recv方法了,而是需要通过on方法提供指定的回调函数,然后在回调函数当中处理。

异步模式的swoole_client必须设置四种回调函数connect、receive、error、close,不能够缺省,否则在调用connect连接时会提示回调未设置。同样,因为已经有了onConnect回调,因此异步模式的swoole_client调用connect方法时不再阻塞,connect方法也只会返回true,此时需要在onConnect回调中确定连接成功,或者在onError回调中确定连接失败。

<?php
/*** 创建异步非阻塞模式下的TCP客户端* 必须设置onConnect、onError、onReceive、onClose* */
$client = new swoole_client(SWOOLE_TCP, SWOOLE_SOCK_ASYNC);//连接成功时回调
$client->on("connect", function(swoole_client $client){//向服务器发送数据$message = "hello world".PHP_EOL;$client->send($message);
});//数据接收时回调
$client->on("receive", function(swoole_client $client, $data){if(empty($data)){$client->close();}else{echo "[receive] $data".PHP_EOL;sleep(1);$client->send(time());}
});//连接失败时回调
$client->on("error", function(swoole_client $client){echo "[error] connection failed".PHP_EOL;
});//注册关闭连接时回调
$client->on("close", function(swoole_client $client){echo "[close] connection close".PHP_EOL;
});//连接到服务器
$host = "127.0.0.1";
$port = 9501;
$timeout = 0.5;//超过与服务器交互的超时秒数会自动断开
if(!$client->connect($host, $port, $timeout)){die("[connect] failed".PHP_EOL);
}


异步模式的swoole_client跟swoole_server一样以事件作为驱动,而无法发像同步模式一样来驱动。只要提供需要的事件就能过够处理逻辑,如swoole的定时器、事件循环等。

例如:实现客户端,每秒向服务器发送一个心跳包,在接收到终端输入的内容后,该客户端会将终端输入的内容发送给服务器。

服务器

$ vim server.php

<?php
//创建TCP服务器并设置IP和端口
$host = "0.0.0.0";
$port = 9501;
$serv = new swoole_server($host, $port);//设置服务器运行时配置
$configs = [];
$configs["worker_num"] = 2;//设置Worker工作进程数量
$configs["task_worker_num"] = 2;//设置Task异步任务的进程数量
$serv->set($configs);//Master主进程 当服务器启动时触发
$serv->on("start", function(swoole_server $serv){echo PHP_EOL."[start] master {$serv->master_pid} manager {$serv->manager_pid}".PHP_EOL;
});//Worker工作进程 当客户端有新TCP连接时触发
$serv->on("connect", function(swoole_server $serv, $fd, $reactor_id){echo PHP_EOL."[connect] worker {$serv->worker_pid} reactor {$reactor_id} client {$fd}".PHP_EOL;
});//Worker工作进程 当客户端连接向服务器发送数据时触发
$serv->on("receive", function(swoole_server $serv, $fd, $reactor_id, $data){echo "[receive] worker {$serv->worker_pid} reactor {$reactor_id} client {$fd} data:{$data}".PHP_EOL;if($data !== "PING"){//投递异步任务给TaskWorker异步任务进程,程序会立即返回向下执行后续代码。$task_id = $serv->task($data);echo "[receive] task {$task_id} data:{$data}".PHP_EOL;//向客户端文件描述符发送字符串信息$message = "success";$serv->send($fd, $message);echo "[receive] client {$fd} send:{$message}".PHP_EOL;}
});//TaskWorker任务进程 处理异步任务
$serv->on("task", function(swoole_server $serv, $task_id, $reactor_id, $data){echo "[task] task {$task_id} reactor {$reactor_id} data:{$data}".PHP_EOL;sleep(10);//模拟异步操作执行时长10秒//返回任务执行的结果$serv->finish("finish");
});//Worker进程 处理异步任务完成的结果
$serv->on("finish", function(swoole_server $serv, $task_id, $data){echo "[finish] worker {$serv->worker_pid} task {$task_id} data:{$data}".PHP_EOL;
});//Worker进程 监听断开连接时触发
$serv->on("close", function(swoole_server $serv, $fd, $reactor_id){//连接断开类型$disconnect_type = "client";//客户端主动断开if($reactor_id < 0){$disconnect_type = "server";//服务器主动断开}echo "[close] worker {$serv->manager_pid} client {$fd} disconnect {$disconnect_type}".PHP_EOL;
});//启动服务器
$serv->start();


客户端

$ vim client.php
<?php
class Client
{private $client;private $timer_id;/**构造函数 */public function __construct($host, $port, $timeout=1){//构建异步非阻塞客户端对象$this->client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC);//绑定事件回调函数$this->client->on("Connect", [$this, "onConnect"]);$this->client->on("Receive", [$this, "onReceive"]);$this->client->on("Close", [$this, "onClose"]);$this->client->on("Error", [$this, "onError"]);//连接服务器$this->client->connect($host, $port, $timeout=1);}/**连接服务器 */public function connect($host, $port, $timeout=1){//连接服务器$fp = $this->client->connect($host, $port, $timeout);if(!$fp){echo "[connect] error{$fp->errCode} {$fp->errMsg}".PHP_EOL;return;}}/**连接成功回调 */public function onConnect($client){//将标准输入添加到swoole的事件监听中swoole_event_add(STDIN, function($fp){//读取标准输入$message = trim(fgets(STDIN));if(!empty($message)){//发送数据$this->client->send($message);}});//添加定时器,每秒向服务器发送一个心跳包$this->timer_id = swoole_timer_tick(1000, function(){$this->client->send("PING");});}public function send($message){$this->client->send($message);}public function onReceive(swoole_client $client, $data){echo "[receive] {$data}".PHP_EOL;}public function onClose(swoole_client $client){$data = json_encode($client);echo "[close] {$data}".PHP_EOL;//断开连接时清除定时器swoole_timer_clear($this->timer_id);}public function onError(swoole_client $client){$data = json_encode($client);echo "[error] {$data}".PHP_EOL;}
}
$client = new Client("127.0.0.1", 9501, 1);


参数3:string $key
$key 表示用于长连接的key,默认使用IP:PORT作为key,相同key的连接会被复用。

对象属性

<?php
$client = new swoole_client(SWOOLE_TCP, SWOOLE_ASYNC);
echo json_encode($client).PHP_EOL;

{"errCode":0,"sock":-1,"reuse":false,"reuseCount":0,"type":1025,"id":null,"setting":null
}


错误码 int swoole_client->errCode
当connect、send、recv、close失败时会自动设置$swoole_client->errCode的值,errCode的值等于Linux的errno,可以使用socket_strerror将错误码转换为错误信息。

$client->on("close", function(swoole_client $client){if(!$client->errCode){$error = socket_strerror($client->errCode);echo "error: {$error}".PHP_EOL;}echo "close".PHP_EOL;
});


Socket文件描述符 int swoole_client->sock
sock属性值为整型的socket文件描述符,可转换int作为数组的key。

// 在PHP代码中可以使用

$sock = fopen("php://fd/".$swoole_client->sock);

  • $client->sock属性值仅在$client->connect后才能取出,在未连接服务器之前此属性值为null。
  • 将swoole_client的socket转换为一个stream socket可调用fread、fwrite、fclose等函数进行操作。
  • swoole_server中的$fd文件描述符不能使用sock()方法转换,因为$fd文件描述符只是一个属于主进程的数字。

是否复用 bool swoole_client->reuse
reuse属性值表示连接是新连接的还是复用已存在的,是一个布尔值,需要与SWOOLE_KEEP配合使用。

例如:WebSocket客户端与服务器建立连接后需要进行握手,如果连接是复用的,就无需再次进行握手,直接发送WebSocket数据帧即可。

if($client->reuse){$client->send($data);
}


建立连接 connect
connect方法用于建立连接到远程服务器

原型

bool $server_client->connect(string $host, int $port, float $timeout = 0.5, int $flag = 0
);


参数
参数1:string $host 表示远程服务器的地址,swoole1.10.0+已支持自动异步解析域名即可直接传入域名。
参数2:int $port 表示远程服务器的端口
参数3:float $timeout 表示网络IO超时秒数,包括connect、send、recv,单位为秒并支持浮点数,默认0.5s即500ms。
参数4:int $flag

  • 在UDP类型时表示是否启用udp_connect设定此选项后将绑定$host与$port,此UDP将会丢弃非指定host/port的数据包。
  • 在TCP类型中$flag=1表示设置为非阻塞socket,connect会立即返回。如果将$flag设置为1则在send/recv前必须使用swoole_client_select来检测是否完成了连接。

模式
同步模式
connect方法在同步模式下会发生阻塞,直到连接成功并返回true。这个时候就可以向服务器发送数据或接收数据了。如果连接失败则会返回false。另外,同步TCP客户端在执行close之后,可以再次发起connect创建新连接到服务器。

if($client->connect($host, $port)){$client->send($message);
}else{echo "connect failed";
}


异步模式
异步模式下connect连接会立即返回true,但实际上连接并未建立,所以不能在connect后使用send。此时使用fsConnected()判断也是false。当连接创建成功后,系统会自动回调onConnect,此时才可以使用send方法向服务器发送数据。

异步客户端执行connect时会增加一次引用计数,当连接关闭时会减少引用计数。

版本

  • 小于swoole1.9.11版本中$timeout超时设置在异步客户端中是无效的,应用层需要使用Timer::after自行添加定时器来实现异步客户端的链接超时控制。
  • 大于等于swoole1.9.11版本中,底层会自动添加定时器,在规定的时间内未连接成功时,底层会触发onError连接失败事件,错误码为ETIMEOUT(110)。

失败重连
connect失败后如果希望重连一次,必须先进行close关闭旧的socket,否则会返回EINPROCESS错误,因为当前的socket正在连接服务器,客户端并不知道是否连接成功,所以无法再次执行connect。

调用close会关闭当前的socket,底层会重新创建新的socket来进行连接。

启用SWOOLE_KEEP长连接后,close调用的第一个参数需要设置为true来表示强行销毁长连接socket。

//连接失败
if($socket->connect($host, $port) === false){$socket->close(true);//关闭旧的socket$socket->connect($host, $port);//重连
}


UDP连接
UDP连接时默认底层并不会启用,一个UDP客户端执行连接时,底层在创建socket后会立即返回成功,此时的socket绑定的地址为0.0.0.0,任何其它对端均可向此端口发送数据包。

$client->connect("192.168.1.100", 9502)


此时操作系统会为客户端socket随机分配一个端口,其它机器可向这个端口发送数据包。

未开启UDP连接时调用getsockname返回的host为0.0.0.0。

将connect的第四项参数$flag设置为1时将启用UDP连接。

$client->connect("192.168.1.100", 9501, 1, 1)


此时将会绑定客户端和服务器,底层会根据服务器的地址来绑定socket绑定的地址,例如连接了192.168.1.100,当前socket会被绑定到192.168.1.*的本地机器上。启用UDP连接后客户端将不再接收其它主机向此端口发送的数据包。

发送数据 send
send方法用于建立连接后发送数据到远程服务器

原型

int $swoole_client->send(string $data);


参数
参数:string $data 发送的数据,格式为字符串,支持二进制。

返回
成功发送返回已发送数据的长度
失败返回false,并设置$swoole_client->errCode错误码。
模式
1.同步

  • 发送的数据没有长度闲置
  • 发送的数据太多时socket缓存区塞满,底层会阻塞等待可写。

2.异步

  • 发送数据的长度收到socket_buffer_size限制
  • 如果socket缓存区已满,swoole的处理逻辑参考swoole_event_write。

注意

  • 如果没有执行连接connect直接调用send会触发PHP警告

接收数据 recv
recv方法用于从服务器接收数据

原型
swoole1.7.22-

string $swoole_client->recv(int $size = 655335, bool $waitall = 0)


swoole1.7.22+

string $swoole_client->recv(int $size = 65535, int $flag = 0);


swoole1.7.22版本后,将原来第二个参数$waitall参数修改为$flags可以接收一些特殊的socket接收设置,为了兼容旧的接口,如果$flag = 1表示 $flag = swoole_client::MSG_WAITALL。

$client->recv(8192, swoole_client::MSG_PEEK | swoole_client::MSG_WAITALL);


参数
int $size 表示接收数据的缓存区最大长度,此参数设置过大会占用较大内存。
bool $waitall 表示是否等待所有数据到达后返回
如果设置了$waitall就必须设定准确的$size否则会一直等待,直到接收的数据长度达到$size。如果未设置$waitall = true时$size最大未64K,如果设置了错误的$size将会导致recv超时而返回false。
 

返回
成功:成功接收到数据则返回字符串
失败:返回false需设置错误码$client->errCode属性
连接关闭:返回空字符串
 

EOL/Length
如果客户端启用了EOF/Length检测后,无需设置$size和$waitall参数,扩展层会返回完整的数据包或返回false。当接收到错误的包头或包头中长度超过package_max_length设置时,recv会返回空字符串,PHP代码中应当关闭此连接。

关闭连接 close
close用于关闭客户端连接,操作成功后返回true。当swoole_client客户端连接被close关闭后不要再次发起连接close。正确的做法是销毁当前的swoole_client,然后再重新创建一个swoole_client并发起新的连接。

bool $swoole_client->close(bool $force = false);


参数:bool $force 表示是否强制关闭连接,可用于关闭SWOOLE_KEEP长连接。
注意:swoole_client对象在析构时会自动关闭

异步非阻塞客户端close关闭时会立即关闭连接,如果发送队列中仍然有数据底层会丢弃。所以请勿在大量发送数据后立即close关闭,否则发送的数据未必能真正到达服务器端。

服务器

$ vim server.php


 

<?php
//创建TCP服务器并设置IP和端口
$host = "0.0.0.0";
$port = 9501;
$server = new swoole_server($host, $port);//设置服务器运行时配置
$configs = [];
$configs["worker_num"] = 2;//设置Worker工作进程数量
$configs["task_worker_num"] = 2;//设置Task异步任务的进程数量
$server->set($configs);//Master主进程 当服务器启动时触发
$server->on("start", function(swoole_server $server){echo PHP_EOL."[start] master {$server->master_pid} manager {$server->manager_pid}".PHP_EOL;
});//Worker工作进程 当客户端有新TCP连接时触发
$server->on("connect", function(swoole_server $server, $fd, $reactor_id){echo PHP_EOL."[connect] worker {$server->worker_pid} reactor {$reactor_id} client {$fd}".PHP_EOL;
});//Worker工作进程 当客户端连接向服务器发送数据时触发
$server->on("receive", function(swoole_server $server, $fd, $reactor_id, $data){echo "[receive] worker {$server->worker_pid} reactor {$reactor_id} client {$fd} data:{$data}".PHP_EOL;if($data !== "PING"){//投递异步任务给TaskWorker异步任务进程,程序会立即返回向下执行后续代码。$task_id = $server->task($data);echo "[receive] task {$task_id} data:{$data}".PHP_EOL;//向客户端文件描述符发送字符串信息$message = "success";$server->send($fd, $message);echo "[receive] client {$fd} send:{$message}".PHP_EOL;}
});//TaskWorker任务进程 处理异步任务
$server->on("task", function(swoole_server $server, $task_id, $reactor_id, $data){echo "[task] task {$task_id} reactor {$reactor_id} data:{$data}".PHP_EOL;sleep(10);//模拟异步操作执行时长10秒//返回任务执行的结果$server->finish("finish");
});//Worker进程 处理异步任务完成的结果
$server->on("finish", function(swoole_server $server, $task_id, $data){echo "[finish] worker {$server->worker_pid} task {$task_id} data:{$data}".PHP_EOL;
});//Worker进程 监听断开连接时触发
$server->on("close", function(swoole_server $server, $fd, $reactor_id){//连接断开类型$disconnect_type = "client";//客户端主动断开if($reactor_id < 0){$disconnect_type = "server";//服务器主动断开}echo "[close] worker {$server->manager_pid} client {$fd} disconnect {$disconnect_type}".PHP_EOL;
});//启动服务器
$server->start();

客户端

$ vim client.php

客户端发送4MB的数据,实际传输可能需要一段时间,此时如果立即进行close关闭操作,可能只有小部分数据传输成功,大部分数据在发送队列中排队等待发送,close关闭时会丢失这些数据。

<?php
$client = new swoole_client(SWOOLE_TCP, SWOOLE_ASYNC);
$client->on("connect", function(swoole_client $client){echo "connect".PHP_EOL;//将标准输入添加到事件监听中swoole_event_add(STDIN, function($fp) use($client){$msg = trim(fgets(STDIN));$client->send($msg);});
});
$client->on("receive", function(swoole_client $client, $data){echo "receive:{$data}".PHP_EOL;$client->send(str_repeat("X", 1024*1024*4).PHP_EOL);$client->close();
});
$client->on("error", function(swoole_client $client){echo "error".PHP_EOL;
});
$client->on("close", function(swoole_client $client){echo "close".PHP_EOL;
});
$client->connect("127.0.0.1", 9501);    


解决方案

配合使用onBufferEmpty等待发送队列为空时进行close操作
 

<?php
$client = new swoole_client(SWOOLE_TCP, SWOOLE_ASYNC);
$client->on("connect", function(swoole_client $client){echo "connect".PHP_EOL;//将标准输入添加到事件监听中swoole_event_add(STDIN, function($fp) use($client){$msg = trim(fgets(STDIN));$client->send($msg);});
});
$client->on("receive", function(swoole_client $client, $data){echo "receive:{$data}".PHP_EOL;$client->send(str_repeat("X", 1024*1024*4).PHP_EOL);$client->close();
});
$client->on("error", function(swoole_client $client){echo "error".PHP_EOL;
});
$client->on("close", function(swoole_client $client){echo "close".PHP_EOL;
});
//配合使用onBufferEmpty等待发送队列为空时进行关闭close操作
$client->on("bufferEmpty", function(swoole_client $client){$client->close();
});
$client->connect("127.0.0.1", 9501);    

  • 协议设计为onReceive收到数据后主动关闭连接,发送数据时对端主动关闭连接。

相关文章:

PHP Swoole Client

PHP常用socket创建TCP连接&#xff0c;使用CURL创建HTTP连接&#xff0c;为了简化操作&#xff0c;Swoole提供了Client类用于实现客户端功能&#xff0c;并增加了异步非阻塞模式&#xff0c;让用户在客户端也能使用事件循环。 作为客户端使用&#xff0c;Swoole Client可以在F…...

《QDebug 2023年12月》

一、Qt Widgets 问题交流 1. 二、Qt Quick 问题交流 1.Q_REVISION 标记的信号槽或者 REVISION 标记的属性&#xff0c;在子类中访问 Q_REVISION 是 Qt 用来做版本控制的一个宏。以 QQuickWindow 为例&#xff0c;继承后去访问 REVISION 标记的 opacity 属性或者 Q_REVISION…...

sklearn 中matplotlib编制图表

代码 # 导入pandas库&#xff0c;并为其设置别名pd import pandas as pd import matplotlib.pyplot as plt# 使用pandas的read_csv函数读取名为iris.csv的文件&#xff0c;将数据存储在iris_data变量中 iris_data pd.read_csv(data/iris.txt,sep\t)# 使用groupby方法按照&quo…...

【Docker-Dev】Mac M2 搭建docker的redis环境

Redis的dev环境docker搭建 1、前言2、官方文档重点信息提取2.1、创建redis实例2.2、使用自己的redis.conf文件。 3、单机版redis搭建4、redis集群版4.1、一些验证4.2、一些问题 结语 1、前言 本文主要针对M2下&#xff0c;相应进行开发环境搭建&#xff0c;然后做一个文档记录…...

docker +gitee+ jenkins +maven项目 (一)

jenkins环境和插件配置 文章目录 jenkins环境和插件配置前言一、环境版本二、jenkins插件三、环境安装总结 前言 现在基本都是走自动化运维&#xff0c;想到用docker 来部署jenkins &#xff0c;然后jenkins来部署java代码&#xff0c;做到了开箱即用&#xff0c;自动发布代码…...

IDEA 开发中常用的快捷键

目录 Ctrl 的快捷键 Alt 的快捷键 Shift 的快捷键 Ctrl Alt 的快捷键 Ctrl Shift 的快捷键 其他的快捷键 Ctrl 的快捷键 Ctrl F 在当前文件进行文本查找 &#xff08;必备&#xff09; Ctrl R 在当前文件进行文本替换 &#xff08;必备&#xff09; Ctrl Z 撤…...

Ubuntu Desktop 死机处理

Ubuntu Desktop 死机处理 当 Ubuntu Desktop 死机时&#xff0c;除了长按电源键重启&#xff0c;还可以使用如下两种方式处理。 方式1&#xff1a;ctrlaltFn 使用 ctrl alt F3~F6: 切换到其他 tty 命令行。 执行 top 命令查看资源占用最多的进程&#xff0c;然后使用 kill…...

Hermite矩阵

Hermite矩阵 文章目录 Hermite矩阵一、正规矩阵【定义】A^H^矩阵【定理】 A^H^的运算性质【定义】正规矩阵、特殊的正规矩阵【定理】与正规矩阵酉相似的矩阵也是正规矩阵【定理】正规的上(下)三角矩阵必为对角矩阵【定义】复向量的内积【定理】Schmitt正交化 二、酉矩阵&#x…...

HTML 实操试题(二)

创建一个简单的HTML文档&#xff1a; 包含<!DOCTYPE html>声明。包含<html>标签&#xff0c;并设置lang属性为英语。包含<head>标签&#xff0c;其中包含<meta charset"UTF-8">和一个自定义的页面标题。包含<body>标签&#xff0c;其…...

MongoDB 面试题

MongoDB 面试题 1. 什么是MongoDB&#xff1f; MongoDB是一种非关系型数据库&#xff0c;被广泛用于大型数据存储和分布式系统的构建。MongoDB支持的数据模型比传统的关系型数据库更加灵活&#xff0c;支持动态查询和索引&#xff0c;也支持BSON格式的数据存储&#xff0c;这…...

LeetCode 1154. 一年中的第几天:2023年最后一道每日一题

【LetMeFly】1154.一年中的第几天&#xff1a;2023年最后一道每日一题 力扣题目链接&#xff1a;https://leetcode.cn/problems/day-of-the-year/ 给你一个字符串 date &#xff0c;按 YYYY-MM-DD 格式表示一个 现行公元纪年法 日期。返回该日期是当年的第几天。 示例 1&…...

《深入理解JAVA虚拟机笔记》OutOfMemoryError 异常

在《Java 虚拟机规范》的规定里&#xff0c;除了程序计数器外&#xff0c;虚拟机内存的其他几个运行时区域都有发生 OutOfMemoryError &#xff08;下文称 OOM&#xff09;异常的可能。 Java堆溢出 Java 堆用于储存对象实例&#xff0c;我们只要不断地创建对象&#xff0c;并…...

R306指纹识别模块指令系统

一&#xff1a;指令集 1. GR_GetImage 指令代码&#xff1a;01H 功能&#xff1a;从传感器上读入图像存于图像缓冲区 2. GR_GenChar 指令代码&#xff1a;02H 功能&#xff1a;根据原始图像生成指纹特征存于 CharBuffer1 或 CharBuffer2 3. GR_Match 指令代码&#xff…...

redis的搭建及应用(三)-Redis主从配置

Redis主从配置 为提升Redis的高可用性&#xff0c;需要搭建多个Redis集群以保证高可用性。常见搭建方式有&#xff1a;主从&#xff0c;哨兵集群等&#xff0c;本节我们搭建一主二从的多Redis架构。 redis主从安装1主2从的方式配置&#xff0c;以端口号为redis的主从文件夹。 主…...

Java学习,一文掌握Java之SpringBoot框架学习文集(1)

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…...

javaWeb学生信息管理系统2

一、学生信息管理系统SIMS 一款基于纯Servlet技术开发的学生信息管理系统&#xff08;SIMS&#xff09;&#xff0c;在设计中没有采用SpringMVC和Spring Boot等框架。系统完全依赖于Servlet来处理HTTP请求和管理学生信息&#xff0c;实现了信息的有效存储、检索和更新&#xf…...

Linux Shell 019-文本行处理工具sed

Linux Shell 019-文本行处理工具sed 本节关键字&#xff1a;Linux、Bash Shell、文本行处理工具 相关指令&#xff1a;sed、 sed介绍 sed是Stream Editor&#xff08;流编辑器&#xff09;的缩写&#xff0c;简称流编辑器&#xff1b;用来处理文件的。sed是一行一行读取文件…...

Ubuntu中fdisk磁盘分区并挂载、扩容逻辑卷

Ubuntu中fdisk磁盘分区并挂载、扩容逻辑卷 一&#xff1a;fdisk磁盘分区并挂载1.查看磁盘分区信息2.分区3.强制系统重新读取分区(避免重启系统)4.格式化分区5.创建挂载目录6.设置开机自动挂载&#xff1a;7.验证并自动挂载(执行了该命令不需要重启系统)8.查看挂载007.异常情况处…...

【leetcode】栈与队列总结

本文内容来自于代码随想录 栈 用栈实现队列 两个栈实现队列。思路&#xff1a;两个栈分别表示入栈和出栈。 入队&#xff1a;直接入栈出队&#xff1a; a. 出栈为空&#xff0c;先把入栈中的元素全部放到出栈中&#xff08;相当于反过来&#xff0c;这样在出栈的时候先进的元…...

[EFI]HP Spectre 13 v102nl电脑 Hackintosh 黑苹果efi引导文件

硬件型号驱动情况主板 HP Spectre 13 v102nl 处理器Intel Core i7-7500U (7th gen - Kaby Lake)已驱动内存8 GB LPDDR3-1866 SDRAM已驱动硬盘512 GB Toshiba NVMe™ M.2 SSD已驱动显卡Intel HD Graphics 620已驱动声卡Conexant CX8200 (0x2008)已驱动网卡I1211 Gigabit Etherne…...

RestClient

什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端&#xff0c;它允许HTTP与Elasticsearch 集群通信&#xff0c;而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级&#xff…...

synchronized 学习

学习源&#xff1a; https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖&#xff0c;也要考虑性能问题&#xff08;场景&#xff09; 2.常见面试问题&#xff1a; sync出…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

React Native在HarmonyOS 5.0阅读类应用开发中的实践

一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强&#xff0c;React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 &#xff08;1&#xff09;使用React Native…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

C++中string流知识详解和示例

一、概览与类体系 C 提供三种基于内存字符串的流&#xff0c;定义在 <sstream> 中&#xff1a; std::istringstream&#xff1a;输入流&#xff0c;从已有字符串中读取并解析。std::ostringstream&#xff1a;输出流&#xff0c;向内部缓冲区写入内容&#xff0c;最终取…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...