1. tcp 服务端简单demo与client .
 <?php
/**
* author : rookiejin <mrjnamei@gmail.com>
* createTime : 2018/1/4 10:26
* description: tcp.php - swoole-demo
* 该代码是一份简单的面向对象形式的 tcp 服务器和客户端通讯的demo
* 功能:实现服务器端tcp简单demo
*/
// 创建一个tcp服务器 $server = new swoole_server("127.0.0.1", 9501); /**
* @var $server swoole_server
* @var $fd int 文件描述符
*/
$server->on("connect", function($server , $fd){
echo "a client connected\n" ;
}); /**
* @var $server swoole_server
* @var $fd int 文件描述符
* @var $from_id worker_id worker进程id
* @var $data 接受的数据
*/
$server->on("receive", function($server , $fd , $from_id ,$data){
echo "#server received msg:" , $data , "\n";
$server->send($fd , "i received");
}); /**
* @var $server swoole_server
* @var $fd 文件描述符
*/
$server->on("close",function($server, $fd){
echo "# client closed\n";
});
// 启动服务器
$server->start();
client.php <?php $client = new swoole_client(SWOOLE_SOCK_TCP); if(!$client->connect("127.0.0.1", 9501, -1)){
exit("connect failed" . $client->errCode . "\n");
} $client->send("helloworld");
echo $client->recv() , "\n";
$client->close();

2. 使用面向对象的方式来写TCP服务器.

 <?php
/**
* author : rookiejin <mrjnamei@gmail.com>
* createTime : 2018/1/4 10:26
* description: php_oop.php - swoole-demo
* 该代码是一份干净的tcp server 事件回调,
* 没有任何对事件回调的业务处理 .
* 以该代码为基准,后面的demo都在此基础上修改 .
*/ class Server { /**
* @var \swoole_server
*/
public $server ; /**
* 配置项
* @var $config array
*/
public $config ; /**
* @var \Server
*/
public static $_worker ; /**
* 存储pid文件的位置
*/
public $pidFile ; /**
* worker 进程的数量
* @var $worker_num
*/
public $worker_num; /**
* 当前进程的worker_id
* @var $worker_id
*/
public $worker_id ; /**
* task 进程数 + worker 进程数 = 总的服务进程
* 给其他的进程发送消息:
* for($i = 0 ; $i < $count ; $i ++) {
* if($i == $this->worker_id) continue;表示是该进程
* $this->server->sendMessage($i , $data);
* }
* task 进程的数量
* @var $task_num
*/
public $task_num ; /**
* Server constructor.
*
* @param array $config
*/
public function __construct(array $config)
{
$this->server = new swoole_server($config ['host'] , $config ['port']);
$this->config = $config;
$this->serverConfig();
self::$_worker = & $this; // 引用
} public function serverConfig()
{
$this->server->set($this->config['server']);
} public function start()
{
// Server启动在主进程的主线程回调此函数
$this->server->on("start",[$this , "onSwooleStart"]);
// 此事件在Server正常结束时发生
$this->server->on("shutDown", [$this , "onSwooleShutDown"]);
//事件在Worker进程/Task进程启动时发生。这里创建的对象可以在进程生命周期内使用。
$this->server->on("workerStart", [$this , "onSwooleWorkerStart"]);
// 此事件在worker进程终止时发生。在此函数中可以回收worker进程申请的各类资源。
$this->server->on("workerStop",[$this, "onSwooleWorkerStop"]);
// worker 向task_worker进程投递任务触发
$this->server->on("task", [$this, "onSwooleTask"]);
// task_worker 返回值传给worker进程时触发
$this->server->on("finish",[$this , "onSwooleFinish"]);
// 当工作进程收到由 sendMessage 发送的管道消息时会触发onPipeMessage事件
$this->server->on("pipeMessage",[$this ,"onSwoolePipeMessage"]);
// 当worker/task_worker进程发生异常后会在Manager进程内回调此函数
$this->server->on("workerError", [$this , "onSwooleWrokerError"]);
// 当管理进程启动时调用它,函数原型:
$this->server->on("managerStart", [$this , "onSwooleManagerStart"]);
// onManagerStop
$this->server->on("managerStop", [$this , "onSwooleManagerStop"]);
// 有新的连接进入时,在worker进程中回调。
$this->server->on("connect" , [$this ,'onSwooleConnect']);
// 接收到数据时回调此函数,发生在worker进程中
$this->server->on("receive", [$this, 'onSwooleReceive']);
//CP客户端连接关闭后,在worker进程中回调此函数。函数原型:
$this->server->on("close", [$this ,"onSwooleClose"]);
$this->server->start();
} /**
* @warning 进程隔离
* 该步骤一般用于存储进程的 master_pid 和 manager_pid 到文件中
* 本例子存储的位置是 __DIR__ . "/tmp/" 下面
* 可以用 kill -15 master_pid 发送信号给进程关闭服务器,并且触发下面的onSwooleShutDown事件
* @param $server
*/
public function onSwooleStart($server)
{
$this->setProcessName('SwooleMaster');
$debug = debug_backtrace();
$this->pidFile = __DIR__ . "/temp/" . str_replace("/" , "_" , $debug[count($debug) - 1] ["file"] . ".pid" );
$pid = [$server->master_pid , $server->manager_pid];
file_put_contents($this->pidFile , implode(",", $pid));
} /**
* @param $server
* 已关闭所有Reactor线程、HeartbeatCheck线程、UdpRecv线程
* 已关闭所有Worker进程、Task进程、User进程
* 已close所有TCP/UDP/UnixSocket监听端口
* 已关闭主Reactor
* @warning
* 强制kill进程不会回调onShutdown,如kill -9
* 需要使用kill -15来发送SIGTREM信号到主进程才能按照正常的流程终止
* 在命令行中使用Ctrl+C中断程序会立即停止,底层不会回调onShutdown
*/
public function onSwooleShutDown($server)
{
echo "shutdown\n";
} /**
* @warning 进程隔离
* 该函数具有进程隔离性 ,
* {$this} 对象从 swoole_server->start() 开始前设置的属性全部继承
* {$this} 对象在 onSwooleStart,onSwooleManagerStart中设置的对象属于不同的进程中.
* 因此这里的pidFile虽然在onSwooleStart中设置了,但是是不同的进程,所以找不到该值.
* @param \swoole_server $server
* @param int $worker_id
*/
public function onSwooleWorkerStart(swoole_server $server, int $worker_id)
{
if($this->isTaskProcess($server))
{
$this->setProcessName('SwooleTask');
}
else{
$this->setProcessName('SwooleWorker');
}
$debug = debug_backtrace();
$this->pidFile = __DIR__ . "/temp/" . str_replace("/" , "_" , $debug[count($debug) - 1] ["file"] . ".pid" );
file_put_contents($this->pidFile , ",{$worker_id}" , FILE_APPEND);
} public function onSwooleWorkerStop($server,$worker_id)
{
echo "#worker exited {$worker_id}\n";
} /**
* @warning 进程隔离 在task_worker进程内被调用
* worker进程可以使用swoole_server_task函数向task_worker进程投递新的任务
* $task_id和$src_worker_id组合起来才是全局唯一的,不同的worker进程投递的任务ID可能会有相同
* 函数执行时遇到致命错误退出,或者被外部进程强制kill,当前的任务会被丢弃,但不会影响其他正在排队的Task
* @param $server
* @param $task_id 是任务ID 由swoole扩展内自动生成,用于区分不同的任务
* @param $src_worker_id 来自于哪个worker进程
* @param $data 是任务的内容
* @return mixed $data
*/
public function onSwooleTask($server , $task_id, $src_worker_id,$data)
{
return $data ;
} public function onSwooleFinish()
{ } /**
* 当工作进程收到由 sendMessage 发送的管道消息时会触发onPipeMessage事件。worker/task进程都可能会触发onPipeMessage事件。
* @param $server
* @param $src_worker_id 消息来自哪个Worker进程
* @param $message 消息内容,可以是任意PHP类型
*/
public function onSwoolePipeMessage($server , $src_worker_id,$message)
{ } /**
* worker进程发送错误的错误处理回调 .
* 记录日志等操作
* 此函数主要用于报警和监控,一旦发现Worker进程异常退出,那么很有可能是遇到了致命错误或者进程CoreDump。通过记录日志或者发送报警的信息来提示开发者进行相应的处理。
* @param $server
* @param $worker_id 是异常进程的编号
* @param $worker_pid 是异常进程的ID
* @param $exit_code 退出的状态码,范围是 1 ~255
* @param $signal 进程退出的信号
*/
public function onSwooleWrokerError($server ,$worker_id,$worker_pid,$exit_code,$signal)
{
echo "#workerError:{$worker_id}\n";
} /**
*
*/
public function onSwooleManagerStart()
{
$this->setProcessName('SwooleManager');
} /**
* @param $server
*/
public function onSwooleManagerStop($server)
{
echo "#managerstop\n";
} /**
* 客户端连接
* onConnect/onClose这2个回调发生在worker进程内,而不是主进程。
* UDP协议下只有onReceive事件,没有onConnect/onClose事件
* @param $server
* @param $fd
* @param $reactorId
*/
public function onSwooleConnect($server ,$fd ,$reactorId)
{
echo "#connected\n";
} /**
* @param $server server对象
* @param $fd 文件描述符
* @param $reactorId reactor线程id
*/
public function onSwooleReceive($server,$fd,$reactorId)
{
echo "#received\n";
} /**
* 连接断开,广播业务需要从redis | memcached | 内存 中删除该fd
* @param $server
* @param $fd
* @param $reactorId
*/
public function onSwooleClose($server, $fd ,$reactorId)
{
echo "#swooleClosed\n" ;
} public function setProcessName($name)
{
if(function_exists('cli_set_process_title'))
{
@cli_set_process_title($name);
}
else{
@swoole_set_process_name($name);
}
} /**
* 返回真说明该进程是task进程
* @param $server
* @return bool
*/
public function isTaskProcess($server)
{
return $server->taskworker === true ;
} /**
* main 运行入口方法
*/
public static function main()
{
self::$_worker->start();
}
} $config = ['server' => ['worker_num' => 4 , "task_worker_num" => "20" , "dispatch_mode" => 3 ] , 'host' => '0.0.0.0' , 'port' => 9501];
$server = new Server($config);
Server::main() ;
  1. 本例子是注册了swoole的基本事件监听,回调没有做,为下面的代码先做一份铺垫。
  2. 这里主要要讲的是swoole的启动步骤.
* note
1. $server = new Server ($config);
在new了一个单例Server类以后,将Server::$_worker代理到本身$this. 并且做好服务器的配置.
2. Server::main();
该代码为server注册事件回调函数. 然后启动 swoole_server::start();

3. 启动过程:
1). 先会开启master进程. 触发onSwooleStart事件,
可以获取到master进程的pid和manager进程的pid.
该函数式在master进程执行的.在事件回调里实例化的任何对象只针对master进程有效.
2). 接着触发onSwooleManagerStart. 在manager进程中执行.
该函数式在master进程执行的.在事件回调里实例化的任何对象只针对manager进程有效.
3). 接着触发onSwooleWorkerStart. 该过程启动worker与task_worker进程.步骤是并行的,
不分先后.
worker进程与task_worker进程其实一样,都属于worker进程,具有进程隔离性,自己进程内
实例化的类只有在自己进程内部有用,
worker_num + worker_task_num = 总的worker_id数量.
如果需要从worker进程向其他进程发送消息的话,可以这么做:
    for($i = 0 ; $i < $worker_num + $task_worker_num ; $i ++) {
if($i == $this->worker_id) continue;
$this->server_sendMessage($i ,$message);
}

4). 然后监听connect与receive事件, 就属于具体的业务范畴了.

下面带来一个 tcp 聊天室的简单案例,例子是用swoole_table存储所有的链接信息. 功能可以实现群聊,单聊: 主要业务逻辑在onSwooleReceive回调中

 <?php
/**
* author : rookiejin <mrjnamei@gmail.com>
* createTime : 2018/1/4 10:26
* description: tcp_get_and_send.php - swoole-demo
* 该代码是一份简单的面向对象形式的 tcp 服务器和客户端通讯的demo
* 功能:单发. 群发.
*/ class Server { /**
* @var \swoole_server
*/
public $server ; /**
* 配置项
* @var $config array
*/
public $config ; /**
* @var \Server
*/
public static $_worker ; /**
* 存储pid文件的位置
*/
public $pidFile ; /**
* worker 进程的数量
* @var $worker_num
*/
public $worker_num; /**
* 当前进程的worker_id
* @var $worker_id
*/
public $worker_id ; /**
* task 进程数 + worker 进程数 = 总的服务进程
* 给其他的进程发送消息:
* for($i = 0 ; $i < $count ; $i ++) {
* if($i == $this->worker_id) continue;表示是该进程
* $this->server->sendMessage($i , $data);
* }
* task 进程的数量
* @var $task_num
*/
public $task_num ; /**
* @var $table swoole_table 内存表
*/
public $table; /**
* Server constructor.
*
* @param array $config
*/
public function __construct(array $config)
{
$this->server = new swoole_server($config ['host'] , $config ['port']);
$this->config = $config;
$this->serverConfig();
$this->createTable();
self::$_worker = & $this; // 引用
} private function serverConfig()
{
$this->server->set($this->config['server']);
} /**
* 创建swoole_table
*/
private function createTable()
{
$this->table = new swoole_table( 65536 );
$this->table->column("fd",swoole_table::TYPE_INT , 8);
$this->table->column("worker_id", swoole_table::TYPE_INT , 4);
$this->table->column("name",swoole_table::TYPE_STRING,255);
$this->table->create();
} public function start()
{
// Server启动在主进程的主线程回调此函数
$this->server->on("start",[$this , "onSwooleStart"]);
// 此事件在Server正常结束时发生
$this->server->on("shutDown", [$this , "onSwooleShutDown"]);
//事件在Worker进程/Task进程启动时发生。这里创建的对象可以在进程生命周期内使用。
$this->server->on("workerStart", [$this , "onSwooleWorkerStart"]);
// 此事件在worker进程终止时发生。在此函数中可以回收worker进程申请的各类资源。
$this->server->on("workerStop",[$this, "onSwooleWorkerStop"]);
// worker 向task_worker进程投递任务触发
$this->server->on("task", [$this, "onSwooleTask"]);
// task_worker 返回值传给worker进程时触发
$this->server->on("finish",[$this , "onSwooleFinish"]);
// 当工作进程收到由 sendMessage 发送的管道消息时会触发onPipeMessage事件
$this->server->on("pipeMessage",[$this ,"onSwoolePipeMessage"]);
// 当worker/task_worker进程发生异常后会在Manager进程内回调此函数
$this->server->on("workerError", [$this , "onSwooleWrokerError"]);
// 当管理进程启动时调用它,函数原型:
$this->server->on("managerStart", [$this , "onSwooleManagerStart"]);
// onManagerStop
$this->server->on("managerStop", [$this , "onSwooleManagerStop"]);
// 有新的连接进入时,在worker进程中回调。
$this->server->on("connect" , [$this ,'onSwooleConnect']);
// 接收到数据时回调此函数,发生在worker进程中
$this->server->on("receive", [$this, 'onSwooleReceive']);
//CP客户端连接关闭后,在worker进程中回调此函数。函数原型:
$this->server->on("close", [$this ,"onSwooleClose"]);
$this->server->start();
} /**
* @warning 进程隔离
* 该步骤一般用于存储进程的 master_pid 和 manager_pid 到文件中
* 本例子存储的位置是 __DIR__ . "/tmp/" 下面
* 可以用 kill -15 master_pid 发送信号给进程关闭服务器,并且触发下面的onSwooleShutDown事件
* @param $server
*/
public function onSwooleStart($server)
{
$this->setProcessName('SwooleMaster');
$debug = debug_backtrace();
$this->pidFile = __DIR__ . "/temp/" . str_replace("/" , "_" , $debug[count($debug) - 1] ["file"] . ".pid" );
$pid = [$server->master_pid , $server->manager_pid];
file_put_contents($this->pidFile , implode(",", $pid));
} /**
* @param $server
* 已关闭所有Reactor线程、HeartbeatCheck线程、UdpRecv线程
* 已关闭所有Worker进程、Task进程、User进程
* 已close所有TCP/UDP/UnixSocket监听端口
* 已关闭主Reactor
* @warning
* 强制kill进程不会回调onShutdown,如kill -9
* 需要使用kill -15来发送SIGTREM信号到主进程才能按照正常的流程终止
* 在命令行中使用Ctrl+C中断程序会立即停止,底层不会回调onShutdown
*/
public function onSwooleShutDown($server)
{
echo "shutdown\n";
} /**
* @warning 进程隔离
* 该函数具有进程隔离性 ,
* {$this} 对象从 swoole_server->start() 开始前设置的属性全部继承
* {$this} 对象在 onSwooleStart,onSwooleManagerStart中设置的对象属于不同的进程中.
* 因此这里的pidFile虽然在onSwooleStart中设置了,但是是不同的进程,所以找不到该值.
* @param \swoole_server $server
* @param int $worker_id
*/
public function onSwooleWorkerStart(swoole_server $server, int $worker_id)
{
if($this->isTaskProcess($server))
{
$this->setProcessName('SwooleTask');
}
else{
$this->setProcessName('SwooleWorker');
}
$debug = debug_backtrace();
$this->pidFile = __DIR__ . "/temp/" . str_replace("/" , "_" , $debug[count($debug) - 1] ["file"] . ".pid" );
file_put_contents($this->pidFile , ",{$worker_id}" , FILE_APPEND);
} public function onSwooleWorkerStop($server,$worker_id)
{
echo "#worker exited {$worker_id}\n";
} /**
* @warning 进程隔离 在task_worker进程内被调用
* worker进程可以使用swoole_server_task函数向task_worker进程投递新的任务
* $task_id和$src_worker_id组合起来才是全局唯一的,不同的worker进程投递的任务ID可能会有相同
* 函数执行时遇到致命错误退出,或者被外部进程强制kill,当前的任务会被丢弃,但不会影响其他正在排队的Task
* @param $server
* @param $task_id 是任务ID 由swoole扩展内自动生成,用于区分不同的任务
* @param $src_worker_id 来自于哪个worker进程
* @param $data 是任务的内容
* @return mixed $data
*/
public function onSwooleTask($server , $task_id, $src_worker_id,$data)
{
// todo
} public function onSwooleFinish()
{
// todo
} /**
* 当工作进程收到由 sendMessage 发送的管道消息时会触发onPipeMessage事件。worker/task进程都可能会触发onPipeMessage事件。
* @param $server
* @param $src_worker_id 消息来自哪个Worker进程
* @param $message 消息内容,可以是任意PHP类型
*/
public function onSwoolePipeMessage($server , $src_worker_id,$message)
{
// todo
} /**
* worker进程发送错误的错误处理回调 .
* 记录日志等操作
* 此函数主要用于报警和监控,一旦发现Worker进程异常退出,那么很有可能是遇到了致命错误或者进程CoreDump。通过记录日志或者发送报警的信息来提示开发者进行相应的处理。
* @param $server
* @param $worker_id 是异常进程的编号
* @param $worker_pid 是异常进程的ID
* @param $exit_code 退出的状态码,范围是 1 ~255
* @param $signal 进程退出的信号
*/
public function onSwooleWrokerError($server ,$worker_id,$worker_pid,$exit_code,$signal)
{
echo "#workerError:{$worker_id}\n";
} /**
*
*/
public function onSwooleManagerStart()
{
$this->setProcessName('SwooleManager');
} /**
* @param $server
*/
public function onSwooleManagerStop($server)
{
echo "#managerstop\n";
} /**
* 客户端连接
* onConnect/onClose这2个回调发生在worker进程内,而不是主进程。
* UDP协议下只有onReceive事件,没有onConnect/onClose事件
* @param $server
* @param $fd
* @param $reactorId
*/
public function onSwooleConnect($server ,$fd ,$reactorId)
{
echo "#{$fd} has connected\n";
$server->send($fd , "please input your name\n");
} /**
* @param $server server对象
* @param $fd 文件描述符
* @param $reactorId reactor线程id
* @param $data 数据
*/
public function onSwooleReceive($server,$fd,$reactorId, $data)
{
$data = json_decode($data, true);
$exist = $this->table->exist($fd);
$from = $data ['from'];
$to = $data ['to'];
$message = $data ['message']; if(!$exist) {
foreach ($this->table as $row)
{
if($row ['name'] == $from)
{
$server->send($fd , 'name already exists');
return ;
}
}
$this->table->set($fd , ['name' => $from , 'fd' => $fd]);
$server->send($fd , "welcome to join tcp chat room\n");
}
// 发送给其他人 .
if($to == 'all')
{
$this->sendToAllExceptHim($server , $message , $fd);
return ;
}
if(!empty($to) && !empty($message))
{
$this->sendToOne($server ,$message ,$to);
}
return ;
} private function sendToOne($server , $message , $name)
{
foreach ($this->table as $row)
{
if($row ['name'] == $name)
{
$server->send($row ['fd'] , $message);
return ;
}
}
} private function sendToAllExceptHim($server , $message, $fd)
{
foreach ($this->table as $row)
{
if($row['fd'] == $fd) continue ;
$server->send($row ['fd'] , $message);
}
} /**
* 连接断开,广播业务需要从redis | memcached | 内存 中删除该fd
* @param $server
* @param $fd
* @param $reactorId
*/
public function onSwooleClose($server, $fd ,$reactorId)
{
$this->table->del($fd);
} public function setProcessName($name)
{
if(function_exists('cli_set_process_title'))
{
@cli_set_process_title($name);
}
else{
@swoole_set_process_name($name);
}
} /**
* 返回真说明该进程是task进程
* @param $server
* @return bool
*/
public function isTaskProcess($server)
{
return $server->taskworker === true ;
} /**
* main 运行入口方法
*/
public static function main()
{
self::$_worker->start();
}
} $config = ['server' => ['worker_num' => 4 , "task_worker_num" => "20" , "dispatch_mode" => 3 ] , 'host' => '0.0.0.0' , 'port' => 9501];
$server = new Server($config);
Server::main() ;

如有错误,敬请纠正!

PHP Swoole-Demo TCP服务端简单实现的更多相关文章

  1. swoole创建TCP服务端和客户端

    服务端: server.php <?php //创建Server对象,监听 127.0.0.1:9501端口    $serv = new swoole_server("127.0.0 ...

  2. python编程系列---tcp服务端的简单实现

    流程如下: """tcp服务端创建流程1. 创建服务端的tcp socket : server_socket 用于监听客户端的请求2. 绑定端口3. server_soc ...

  3. TCP/UDP简易通信框架源码,支持轻松管理多个TCP服务端(客户端)、UDP客户端

    目录 说明 TCP/UDP通信主要结构 管理多个Socket的解决方案 框架中TCP部分的使用 框架中UDP部分的使用 框架源码结构 补充说明 源码地址 说明 之前有好几篇博客在讲TCP/UDP通信方 ...

  4. 【转】TCP/UDP简易通信框架源码,支持轻松管理多个TCP服务端(客户端)、UDP客户端

    [转]TCP/UDP简易通信框架源码,支持轻松管理多个TCP服务端(客户端).UDP客户端 目录 说明 TCP/UDP通信主要结构 管理多个Socket的解决方案 框架中TCP部分的使用 框架中UDP ...

  5. vertx 从Tcp服务端和客户端开始翻译

    写TCP 服务器和客户端 vert.x能够使你很容易写出非阻塞的TCP客户端和服务器 创建一个TCP服务 最简单的创建TCP服务的方法是使用默认的配置:如下 NetServer server = ve ...

  6. 子进程回收资源两种方式,僵尸进程与孤儿进程,守护进程,进程间数据隔离,进程互斥锁,队列,IPC机制,线程,守护线程,线程池,回调函数add_done_callback,TCP服务端实现并发

    子进程回收资源两种方式 - 1) join让主进程等待子进程结束,并回收子进程资源,主进程再结束并回收资源. - 2) 主进程 “正常结束” ,子进程与主进程一并被回收资源. from multipr ...

  7. 基于Select模型的Windows TCP服务端和客户端程序示例

    最近跟着刘远东老师的<C++百万并发网络通信引擎架构与实现(服务端.客户端.跨平台)>,Bilibili视频地址为C++百万并发网络通信引擎架构与实现(服务端.客户端.跨平台),重新复习下 ...

  8. C++封装的基于WinSock2的TCP服务端、客户端

    无聊研究Winsock套接字编程,用原生的C语言接口写出来的代码看着难受,于是自己简单用C++封装一下,把思路过程理清,方便自己后续翻看和新手学习. 只写好了TCP通信服务端,有空把客户端流程也封装一 ...

  9. 利用select实现IO多路复用TCP服务端

    一.相关函数 1.  int select(int maxfdp, fd_set *readset, fd_set *writeset, fd_set *exceptset,struct timeva ...

随机推荐

  1. [Luogu3420][POI2005]SKA-Piggy Banks

    题目描述 Byteazar the Dragon has NNN piggy banks. Each piggy bank can either be opened with its correspo ...

  2. opensuse下安装redis

    1.安装gcc zypper install gcc 2.解压,安装到指定路径 sudo tar xzf redis-4.0.1.tar.gzcd redis#安装到指定目录中sudo make PR ...

  3. golang会取代php吗

    看看PHP和Golang如何在开发速度,性能,安全性,可伸缩性等方面展开合作. PHP与Golang比较是一个艰难的比较. PHP最初创建于1994年,已有24年.自那时起,由于PHP的开源格式,易用 ...

  4. python学习-异常处理之捕获异常与抛出异常(七)

    捕获异常 python完整的异常处理语法结构如下: 特别说明: 1.try块是必需的,except块和finally,当try块没有出现异常时,程序会执行else块 2.try块后只有一个except ...

  5. chrome devtools tip(1)--调试伪类

    开发中我们经常遇到,添加些focus,hover事件,样式,但当我们去打开 chrome devtools,浮动上去的时候,然后准备去改变样式的时候,结果由于光标移动了,样式不见了,非常不方便调试,其 ...

  6. OptimalSolution(8)--位运算

    一.不用额外变量交换两个整数的值 如果给定整数a和b,用以下三行代码即可交换a和b的值.a = a ^ b; b = a ^ b; a = a ^ b; a = a ^ b :假设a异或b的结果记为c ...

  7. map 与 set的使用

    1.map的使用 初始化的两种方式 a. const map = new Map([['name','ouycx'],['age', 20]]); b. const map = new Map(); ...

  8. (八十六)c#Winform自定义控件-表格优化

    出处:http://www.hzhcontrols.com/原文:http://www.hzhcontrols.com/blog-149.html本文版权归www.hzhcontrols.com所有欢 ...

  9. WebApi -用户登录后SessionId未更新

    描工具检测出.net的程序有会话标识未更新这个漏洞 用户尚未登录时就有session cookie产生.可以尝试在打开页面的时候,让这个cookie过期.等到用户再登陆的时候就会生成一个新的sessi ...

  10. win10+MinGw+ffmpeg 编译

    一.安装MinGw+msys 下载 mingw-get-setup.exe 并安装,安装完成会弹出以下界面. 选中红色框几个选项,点击Installation->Apply Changes 进行 ...