网页实时聊天之PHP如何实现websocket

时间:2022-09-13 22:52:30

网页实时聊天之PHP如何实现websocket

一、总结

一句话总结:

应用 PHP 的 socket 函数库:PHP 的 socket 函数库跟 C 语言的 socket 函数非常类似

PHP 实现 websocket 的话,主要是应用 PHP 的 socket 函数库,PHP 的 socket 函数库跟 C 语言的 socket 函数非常类似

1、websocket作用?

打破了 http “请求-响应”的常规思维,实现了服务器向客户端主动推送消息

WebSocket 不是一门技术,而是一种全新的协议。

它应用 TCP 的 Socket(套接字),为网络应用定义了一个新的重要的能力:客户端和服务器端的双全工传输和双向通信。是继 Java applets、 XMLHttpRequest、 Adobe Flash,、ActiveXObject、 各类 Comet 技术之后,服务器推送客户端消息的新趋势。

2、服务器推送客户端消息的各种方式?

Java applets、 XMLHttpRequest、 Adobe Flash、 ActiveXObject、 各类 Comet、 websocket

3、websocket与http的关系?

都是应用层的协议,它们都是基于 tcp 传输层,握手成功后,websocket 就使用自己的协议规定的方式进行通讯,跟 http 就没有关系了

在网络分层上,websocket 与 http 协议都是应用层的协议,它们都是基于 tcp 传输层的,但是 websocket 在建立连接时,是借用 http 的 101 switch protocol 来达到协议转换(Upgrade)的,从 HTTP 协议切换成 WebSocket 通信协议,这个动作协议中称“握手”;

握手成功后,websocket 就使用自己的协议规定的方式进行通讯,跟 http 就没有关系了。

4、socket和用户的关系?

每一个 socket 代表一个用户

但作为服务器,是必须要对已经连接的 socket 进行存储和识别的。每一个 socket 代表一个用户,如何关联和查询用户信息与 socket 的对应就是一个问题了

5、C 语言的 socket 的实现的原理是什么?

一个个的’文件描述符‘:每一个 socket 都对应一个文件,读写 socket 都是操作对应的文件

C 语言的 socket 的实现便是一个个的’文件描述符‘ ,这个文件描述符一般是打开文件的顺序递增的 int 数值,从 0 一直递增(当然系统是有限制的)。每一个 socket 都对应一个文件,读写 socket 都是操作对应的文件,所以也能像文件系统一样应用 read 和 write 函数。

6、php的socket的结构?

数组结构,里面有端口,ip,姓名,socket对象等
$connected_sockets = array(
(int)$socket => array(
'resource' => $socket,
'name' => $name,
'ip' => $ip,
'port' => $port,
...
)
)

7、php如何创建服务器socket?

创建socket,设置socket选项,socket绑定ip和端口,socket监听
// 创建一个 TCP socket, 此函数的可选值在官方文档中写得十分详细,这里不再提了
$this->master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
// 设置IP和端口重用,在重启服务器后能重新使用此端口;
socket_set_option($this->master, SOL_SOCKET, SO_REUSEADDR, 1);
// 将IP和端口绑定在服务器socket上;
socket_bind($this->master, $host, $port);
// listen函数使主动连接套接口变为被连接套接口,使得此 socket 能被其他 socket 访问,从而实现服务器功能。后面的参数则是自定义的待处理socket的最大数目,并发高的情况下,这个值可以设置大一点,虽然它也受系统环境的约束。
socket_listen($this->master, self::LISTEN_SOCKET_NUM);

8、PHP实现websocket的服务器逻辑是什么?

创建socket、接受客户端连接、处理消息、反应客户端中断
$write = $except = NULL;
$sockets = array_column($this->sockets, 'resource'); // 获取到全部的 socket 资源
$read_num = socket_select($sockets, $write, $except, NULL); foreach ($sockets as $socket) {
// 如果可读的是服务器 socket, 则处理连接逻辑;
if ($socket == $this->master) {
socket_accept($this->master);
// socket_accept() 接受 请求 “正在 listen 的 socket(像我们的服务器 socket )” 的连接, 并一个客户端 socket, 错误时返回 false;
self::connect($client);
continue;
}
// 如果可读的是其他已连接 socket ,则读取其数据,并处理应答逻辑
} else {
// 函数 socket_recv() 从 socket 中接受长度为 len 字节的数据,并保存在 $buffer 中。
$bytes = @socket_recv($socket, $buffer, 2048, 0); if ($bytes < 9) {
// 当客户端忽然中断时,服务器会接收到一个 8 字节长度的消息(由于其数据帧机制,8字节的消息我们认为它是客户端异常中断消息),服务器处理下线逻辑,并将其封装为消息广播出去
$recv_msg = $this->disconnect($socket);
} else {
// 如果此客户端还未握手,执行握手逻辑
if (!$this->sockets[(int)$socket]['handshake']) {
self::handShake($socket, $buffer);
continue;
} else {
$recv_msg = self::parse($buffer);
}
} // 广播消息
$this->broadcast($msg);
}
}
}

9、PHP实现websocket的客户端逻辑是什么?

前端我们使用 js 调用 Websocket 方法很简单就能创建一个 websocket 连接,服务器会为帮我们完成连接、握手的操作,js 使用事件机制来处理浏览器与服务器的交互:
// 创建一个 websocket 连接
var ws = new WebSocket("ws://127.0.0.1:8080"); // websocket 创建成功事件
ws.onopen = function () {
}; // websocket 接收到消息事件
ws.onmessage = function (e) {
var msg = JSON.parse(e.data);
} // websocket 错误事件
ws.onerror = function () {
}; 发送消息也很简单,直接调用 ws.send(msg) 方法就行了。

10、socket是技术还是是协议?

WebSocket 不是一门技术,而是一种全新的协议。

它应用 TCP 的 Socket(套接字),为网络应用定义了一个新的重要的能力:客户端和服务器端的双全工传输和双向通信。是继 Java applets、 XMLHttpRequest、 Adobe Flash,、ActiveXObject、 各类 Comet 技术之后,服务器推送客户端消息的新趋势。

二、网页实时聊天之PHP实现websocket、(转)

转自:网页实时聊天之PHP实现websocket - 枕边书 - 博客园
https://www.cnblogs.com/zhenbianshu/p/6111257.html

h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h4:first-child, body>h5:first-child, body>h6:first-child {
margin-top: 0;
padding-top: 0;
}

a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0;
}

h1+p, h2+p, h3+p, h4+p, h5+p, h6+p {
margin-top: 10px;
}

/* LINKS
=============================================================================*/

a {
color: #4183C4;
text-decoration: none;
}

a:hover {
text-decoration: underline;
}

/* LISTS
=============================================================================*/

ul, ol {
padding-left: 30px;
}

ul li > :first-child,
ol li > :first-child,
ul li ul:first-of-type,
ol li ol:first-of-type,
ul li ol:first-of-type,
ol li ul:first-of-type {
margin-top: 0px;
}

ul ul, ul ol, ol ol, ol ul {
margin-bottom: 0;
}

dl {
padding: 0;
}

dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px;
}

dl dt:first-child {
padding: 0;
}

dl dt>:first-child {
margin-top: 0px;
}

dl dt>:last-child {
margin-bottom: 0px;
}

dl dd {
margin: 0 0 15px;
padding: 0 15px;
}

dl dd>:first-child {
margin-top: 0px;
}

dl dd>:last-child {
margin-bottom: 0px;
}

/* CODE
=============================================================================*/

pre, code, tt {
font-size: 12px;
font-family: Consolas, "Liberation Mono", Courier, monospace;
}

code, tt {
margin: 0 0px;
padding: 0px 0px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px;
}

pre>code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent;
}

pre {
background-color: #f8f8f8;
border: 1px solid #ccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px;
}

pre code, pre tt {
background-color: transparent;
border: none;
}

kbd {
-moz-border-bottom-colors: none;
-moz-border-left-colors: none;
-moz-border-right-colors: none;
-moz-border-top-colors: none;
background-color: #DDDDDD;
background-image: linear-gradient(#F1F1F1, #DDDDDD);
background-repeat: repeat-x;
border-color: #DDDDDD #CCCCCC #CCCCCC #DDDDDD;
border-image: none;
border-radius: 2px 2px 2px 2px;
border-style: solid;
border-width: 1px;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
line-height: 10px;
padding: 1px 4px;
}

/* QUOTES
=============================================================================*/

blockquote {
border-left: 4px solid #DDD;
padding: 0 15px;
color: #777;
}

blockquote>:first-child {
margin-top: 0px;
}

blockquote>:last-child {
margin-bottom: 0px;
}

/* HORIZONTAL RULES
=============================================================================*/

hr {
clear: both;
margin: 15px 0;
height: 0px;
overflow: hidden;
border: none;
background: transparent;
border-bottom: 4px solid #ddd;
padding: 0;
}

/* TABLES
=============================================================================*/

table th {
font-weight: bold;
}

table th, table td {
border: 1px solid #ccc;
padding: 6px 13px;
}

table tr {
border-top: 1px solid #ccc;
background-color: #fff;
}

table tr:nth-child(2n) {
background-color: #f8f8f8;
}

/* IMAGES
=============================================================================*/

img {
max-width: 100%
}
-->

前言

websocket 作为 HTML5 里一个新的特性一直很受人关注,因为它真的非常酷,打破了 http “请求-响应”的常规思维,实现了服务器向客户端主动推送消息,本文介绍如何使用 PHP 和 JS 应用 websocket 实现一个网页实时聊天室;

以前写过一篇文章讲述如何使用ajax长轮询实现网页实时聊天,见链接: 网页实时聊天之js和jQuery实现ajax长轮询 ,但是轮询和服务器的 pending 都是无谓的消耗,websocket 才是新的趋势。

最近艰难地“挤”出了一点时间,完善了很早之前做的 websocket “请求-原样返回”服务器,用js完善了下客户端功能,把过程和思路分享给大家,顺便也普及一下 websocket 相关的知识,当然现在讨论 websocket 的文章也特别多,有些理论性的东西我也就略过了,给出参考文章供大家选择阅读。

正文开始前,先贴一张聊天室的效果图(请不要在意CSS渣的页面):

网页实时聊天之PHP如何实现websocket

然后当然是源码: 我是源码链接 - github - 枕边书


websocket

简介

WebSocket 不是一门技术,而是一种全新的协议。它应用 TCP 的 Socket(套接字),为网络应用定义了一个新的重要的能力:客户端和服务器端的双全工传输和双向通信。是继 Java applets、 XMLHttpRequest、 Adobe Flash,、ActiveXObject、 各类 Comet 技术之后,服务器推送客户端消息的新趋势。

与http的关系

在网络分层上,websocket 与 http 协议都是应用层的协议,它们都是基于 tcp 传输层的,但是 websocket 在建立连接时,是借用 http 的 101 switch protocol 来达到协议转换(Upgrade)的,从 HTTP 协议切换成 WebSocket 通信协议,这个动作协议中称“握手”;

握手成功后,websocket 就使用自己的协议规定的方式进行通讯,跟 http 就没有关系了。

握手

以下是一个我自己的浏览器发送的典型的握手 http 头:

网页实时聊天之PHP如何实现websocket

服务器收到握手请求后,提取出请求头中的 “Sec-WebSocket-Key” 字段,追回一个固定的字符串 ‘258EAFA5-E914-47DA-95CA-C5AB0DC85B11’, 然后进行 sha1 加密,最后转换为 base64 编码,作为 key 以 “Sec-WebSocket-Accept” 字段返回给客户端,客户端匹配此 key 后,便建立了连接,完成了握手;

数据传输

websocket 有自己规定的数据传输格式,称为 帧(Frame),下图是一个数据帧的结构,其中单位为bit:

  0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+---------------------------------------------------------------+

具体每个字段是什么意思,有兴趣的可以看一下这篇文章 The WebSocket Protocol 5.数据帧 感觉自己对二进制的操作还不是很灵活,也就没有挑战自己写算法解析数据了,下面的数据帧解析和封装都是使用的网上的算法。

不过,我工作中写支付网关中还是会经常用到数据的进制操作的,这个一定是要仔细研究总结一下的,嗯,先记下。


PHP 实现 websocket 服务器

PHP 实现 websocket 的话,主要是应用 PHP 的 socket 函数库:

PHP 的 socket 函数库跟 C 语言的 socket 函数非常类似,以前翻过一遍 APUE, 所以觉得还挺好理解。在 PHP 手册中看一遍 socket 函数,我想大家也能对 php 的 socket 编程有一定的认识。

下面会在代码中对所用函数进行简单的注释。

文件描述符

忽然提及'文件描述符',大家可能会有些奇怪。

但作为服务器,是必须要对已经连接的 socket 进行存储和识别的。每一个 socket 代表一个用户,如何关联和查询用户信息与 socket 的对应就是一个问题了,这里便应用了关于文件描述符的一点小技巧。

我们知道 linux 是'万物皆文件'的,C 语言的 socket 的实现便是一个个的’文件描述符‘ ,这个文件描述符一般是打开文件的顺序递增的 int 数值,从 0 一直递增(当然系统是有限制的)。每一个 socket 都对应一个文件,读写 socket 都是操作对应的文件,所以也能像文件系统一样应用 read 和 write 函数。

tips: linux 中, 标准输入对应的是文件描述符 0;标准输出对应的文件描述符是 1; 标准错误对应的文件描述符是 2;所以我们可以使用 0 1 2对输入输出重定向。

那么类似于 C socket 的 PHP socket 自然也继承了这一点,它创建的 socket 也是类型于 int 值为 4 5 之类的资源类型。 我们可以使用 (int) 或 intval() 函数把 socket 转换为一个唯一的ID,从而可以实现用一个 ’类索引数组‘ 来存储 socket 资源和对应的用户信息;

结果类似:

$connected_sockets = array(
(int)$socket => array(
'resource' => $socket,
'name' => $name,
'ip' => $ip,
'port' => $port,
...
)
)

创建服务器socket

下面是一段创建服务器 socket 的代码:

// 创建一个 TCP socket, 此函数的可选值在官方文档中写得十分详细,这里不再提了
$this->master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
// 设置IP和端口重用,在重启服务器后能重新使用此端口;
socket_set_option($this->master, SOL_SOCKET, SO_REUSEADDR, 1);
// 将IP和端口绑定在服务器socket上;
socket_bind($this->master, $host, $port);
// listen函数使主动连接套接口变为被连接套接口,使得此 socket 能被其他 socket 访问,从而实现服务器功能。后面的参数则是自定义的待处理socket的最大数目,并发高的情况下,这个值可以设置大一点,虽然它也受系统环境的约束。
socket_listen($this->master, self::LISTEN_SOCKET_NUM);

这样,我们就得到一个服务器 socket,当有客户端连接到此 socket 上时,它将改变状态为可读,那就看接下来服务器的处理逻辑了。

服务器逻辑

这里着重讲一下 socket_select($read, $write, $except, $tv_sec [, $tv_usec]):

select 函数使用传统的 select 模型,可读、写、异常的 socket 会被分别放入 $socket, $write, $except 数组中,然后返回 状态改变的 socket 的数目,如果发生了错误,函数将会返回 false.

需要注意的是最后两个时间参数,它们只有单位不同,可以搭配使用,用来表示 socket_select 阻塞的时长,为0时此函数立即返回,可以用于轮询机制。 为 NULL 时,函数会一直阻塞下去, 这里我们置 $tv_sec 参数为null,让它一直阻塞,直到有可操作的 socket 返回。

下面是服务器的主要逻辑:

$write = $except = NULL;
$sockets = array_column($this->sockets, 'resource'); // 获取到全部的 socket 资源
$read_num = socket_select($sockets, $write, $except, NULL); foreach ($sockets as $socket) {
// 如果可读的是服务器 socket, 则处理连接逻辑;
if ($socket == $this->master) {
socket_accept($this->master);
// socket_accept() 接受 请求 “正在 listen 的 socket(像我们的服务器 socket )” 的连接, 并一个客户端 socket, 错误时返回 false;
self::connect($client);
continue;
}
// 如果可读的是其他已连接 socket ,则读取其数据,并处理应答逻辑
} else {
// 函数 socket_recv() 从 socket 中接受长度为 len 字节的数据,并保存在 $buffer 中。
$bytes = @socket_recv($socket, $buffer, 2048, 0); if ($bytes < 9) {
// 当客户端忽然中断时,服务器会接收到一个 8 字节长度的消息(由于其数据帧机制,8字节的消息我们认为它是客户端异常中断消息),服务器处理下线逻辑,并将其封装为消息广播出去
$recv_msg = $this->disconnect($socket);
} else {
// 如果此客户端还未握手,执行握手逻辑
if (!$this->sockets[(int)$socket]['handshake']) {
self::handShake($socket, $buffer);
continue;
} else {
$recv_msg = self::parse($buffer);
}
} // 广播消息
$this->broadcast($msg);
}
}
}

这里只是服务器处理消息的基础代码,日志记录和异常处理都略过了,而且还有些数据帧解析和封装的方法,各位也不一定看爱,有兴趣的可以去 github 上支持一下我的源码~~

此外,为了便于服务器与客户端的交互,我自己定义了 json 类型的消息格式,形似:

$msg = [
'type' => $msg_type, // 有普通消息,上下线消息,服务器消息
'from' => $msg_resource, // 消息来源
'content' => $msg_content, // 消息内容
'user_list' => $uname_list, // 便于同步当前在线人数与姓名
];

客户端

创建客户端

前端我们使用 js 调用 Websocket 方法很简单就能创建一个 websocket 连接,服务器会为帮我们完成连接、握手的操作,js 使用事件机制来处理浏览器与服务器的交互:

// 创建一个 websocket 连接
var ws = new WebSocket("ws://127.0.0.1:8080"); // websocket 创建成功事件
ws.onopen = function () {
}; // websocket 接收到消息事件
ws.onmessage = function (e) {
var msg = JSON.parse(e.data);
} // websocket 错误事件
ws.onerror = function () {
};

发送消息也很简单,直接调用 ws.send(msg) 方法就行了。

页面功能

页面部分主要是让用户使用起来方便,这里给消息框 textarea 添加了一个键盘监控事件,当用户按下回车键时直接发送消息;

function confirm(event) {
var key_num = event.keyCode;
if (13 == key_num) {
send();
} else {
return false;
}
}

还有用户打开客户端时生成一个默认唯一用户名;

然后是一些对数据的解析构造,对客户端页面的更新,这里就不再啰嗦了,感兴趣的可以看源码。

用户名异步处理

这里不得不提一下用户登陆时确定用户名时的一个小问题,我原来是想在客户端创建一个连接后直接发送用户名到服务器,可是控制台里报出了 “websocket 仍在连接中或已关闭” 的错误信息。

Uncaught DOMException: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state.

考虑到连接可能还没处理好,我就实现了 sleep 方法等了一秒再发送用户名,可是错误仍然存在。

后来忽然想到 js 的单线程阻塞机制,才明白使用 sleep 一直阻塞也是没有用的,利用好 js 的事件机制才是正道:于是在服务器端添加逻辑,在握手成功后,向客户端发送握手已成功的消息;客户端先将用户名存入一个全局变量,接收到服务器的握手成功的提醒消息后再发送用户名,于是成功在第一时间更新用户名。


小结

聊天室扩展方向

简易聊天室已经完成,当然还要给它带有希望的美好未来,希望有人去实现:

  • 页面美化(信息添加颜色等)
  • 服务器识别 '@' 字符而只向某一个 socket 写数据实现聊天室的私聊;
  • 多进程(使用 redis 等缓存数据库来实现资源的共享),可参考我以前的一篇文章: 初探PHP多进程
  • 消息记录数据库持久化(log 日志还是不方便分析)
  • ...

总结

多读些经典书籍还是很有用的,有些东西真的是触类旁通,APUE/UNP 还是要再多翻几遍。此外互联网技术日新月异,挑一些自己喜欢的学习一下,跟大家分享一下也是挺舒服的(虽然程序和博客加一块用了至少10个小时...)。

参考:

websocket协议翻译

刨根问底 HTTP 和 WebSocket 协议(下)

学习WebSocket协议—从顶层到底层的实现原理(修订版)

嗯,持续更新。喜欢的可以点个推荐或关注,有错漏之处,请指正,谢谢。

 

网页实时聊天之PHP如何实现websocket的更多相关文章

  1. 网页实时聊天之PHP实现websocket

    html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...

  2. 网页实时聊天之js和jQuery实现ajax长轮询

    众所周知,HTTP协议是无状态的,所以一次的请求都是一个单独的事件,和前后都没有联系.所以我们在解决网页实时聊天时就遇到一个问题,如何保证与服务器的长时间联系,从而源源不段地获取信息. 一直以来的方式 ...

  3. &lbrack;转&rsqb;网页实时聊天之js和jQuery实现ajax长轮询 PHP

    网页实时聊天之js和jQuery实现ajax长轮询 众所周知,HTTP协议是无状态的,所以一次的请求都是一个单独的事件,和前后都没有联系.所以我们在解决网页实时聊天时就遇到一个问题,如何保证与服务器的 ...

  4. SignalR实现网页实时聊天功能

    SignalR是利用html5 sokit方式实现网页的实时性,在客户端不支持html5的情况下通过轮询实现 实现原理是客户端发送的消息先去服务器,然后服务器根据需要将消息广播到需要接收信息的客户群. ...

  5. php websocket-网页实时聊天之PHP实现websocket(ajax长轮询和websocket都可以时间网络聊天室)

    php websocket-网页实时聊天之PHP实现websocket(ajax长轮询和websocket都可以时间网络聊天室) 一.总结 1.ajax长轮询和websocket都可以时间网络聊天室 ...

  6. Spring&plus;WebSocket&plus;SockJS实现实时聊天

    设计初衷是通过websocket实现网页实时通讯聊天. 工程环境:tomcat8+jdk1.7+maven+eclipse 设计思路:客户端登录网页建立socket连接,后台记录用户连接信息并做标识: ...

  7. Springboot整合WebSocket实现网页版聊天,快来围观!

  8. 基于swoole的网页一对一实时聊天

    需求分析 网站上实现一对一即时沟通,能查看聊天记录以及离线留言,新消息提醒. 核心技术 html5的websocket,php的swoole扩展http://wiki.swoole.com/ 数据表 ...

  9. vue&plus;websocket&plus;express&plus;mongodb实战项目(实时聊天)

    继上一个项目用vuejs仿网易云音乐(实现听歌以及搜索功能)后,发现上一个项目单纯用vue的model管理十分混乱,然后我去看了看vuex,打算做一个项目练练手,又不想做一个重复的项目,这次我就放弃颜 ...

随机推荐

  1. FMDB 多线程使用

    在App中保持一个FMDatabaseQueue的实例,并在所有的线程中都只使用这一个实例. [FMDatabaseQueue databaseQueueWithPath:path]; FMDatab ...

  2. Zookeeper知识点

    Zookeeper是一个分布式协调服务 Zookeeper服务器的角色 Leader: 所有的写操作必须要经过Leader完成,在广播给其它服务器.心跳检测.集群中只有一个Leader. Follow ...

  3. MySQL全备&plus;binlog恢复方法之伪装master【原创】

    利用mysql全备 +binlog server恢复方法之伪装master 单实例试验 一.试验环境 10.72.7.40 实例 mysql3306为要恢复的对象,mysql3306的全备+binlo ...

  4. sql server 存储过程使用游标记录

    sql server 存储过程使用游标记录--方便下次参考使用 游标的组成: 声明游标 打卡游标 从一个游标中查找信息 关闭游标 释放游标 游标类型: 静态游标 动态游标 只进游标 键集驱动游标 静态 ...

  5. thymeleaf 获取sessionid

    参考https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html ${#session.id}

  6. Gitlab&plus;Jenkins学习之路(十一)之Jenkins自动触发构建和发布

    思路图: 一.下载gitlab plugin jenkins-->系统管理-->管理插件-->下载并安装gitlab plugin 二.配置gitlab认证 路径:Jenkins-- ...

  7. CUDA Samples&colon; dot product&lpar;使用零拷贝内存&rpar;

    以下CUDA sample是分别用C++和CUDA实现的点积运算code,CUDA包括普通实现和采用零拷贝内存实现两种,并对其中使用到的CUDA函数进行了解说,code参考了<GPU高性能编程C ...

  8. 《iOS用户体验》总结与思考-改动版

    假设转载此文.请注明出处:http://blog.csdn.net/paulery2012/article/details/25157347,谢谢. 前言: 本文是在阅读<ios用户体验> ...

  9. Qt 学习之路 2(45):模型

    Home / Qt 学习之路 2 / Qt 学习之路 2(45):模型 Qt 学习之路 2(45):模型  豆子  2013年2月26日  Qt 学习之路 2  23条评论 在前面两章的基础之上,我们 ...

  10. codeforces 427 div&period;2 F&period; Roads in the Kingdom

    F. Roads in the Kingdom time limit per test 2 seconds memory limit per test 256 megabytes input stan ...