【Zookeeper】源码分析之网络通信(一)
一、前言
前面已经分析了请求处理链中的多数类,接着继续分析Zookeeper中的网络通信模块。
二、总体框图
对于网络通信模块,其总体框图如下所示
  
说明:
Stats,表示ServerCnxn上的统计数据。
Watcher,表示时间处理器。
ServerCnxn,表示服务器连接,表示一个从客户端到服务器的连接。
NettyServerCnxn,基于Netty的连接的具体实现。
NIOServerCnxn,基于NIO的连接的具体实现。
三、ServerCnxn源码分析
3.1 类的继承关系
public abstract class ServerCnxn implements Stats, Watcher {}
说明:ServerCnxn为抽象类,其继承Stats和Watcher两个接口,表示客户端到服务端的连接。
3.2 类的内部类
// 请求关闭异常类
protected static class CloseRequestException extends IOException {
private static final long serialVersionUID = -7854505709816442681L; public CloseRequestException(String msg) {
super(msg);
}
} // 流结束异常类
protected static class EndOfStreamException extends IOException {
private static final long serialVersionUID = -8255690282104294178L; public EndOfStreamException(String msg) {
super(msg);
} public String toString() {
return "EndOfStreamException: " + getMessage();
}
}
说明:ServerCnxn包含了两个异常类,用于表示在连接中发生的异常情况。
3.3 类的属性
public abstract class ServerCnxn implements Stats, Watcher {
    // This is just an arbitrary object to represent requests issued by
    // (aka owned by) this class
    // 代表由本类提出的请求
    final public static Object me = new Object();
    // 认证信息
    protected ArrayList<Id> authInfo = new ArrayList<Id>();
    /**
     * If the client is of old version, we don't send r-o mode info to it.
     * The reason is that if we would, old C client doesn't read it, which
     * results in TCP RST packet, i.e. "connection reset by peer".
     */
    // 是否为旧的C客户端
    boolean isOldClient = true;
    // Zookeeper的Sasl服务器
    protected ZooKeeperSaslServer zooKeeperSaslServer = null;
    /**
    * CMD命令
    **/
    /*
     * See <a href="{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands">
     * Zk Admin</a>. this link is for all the commands.
     */
    // CMD命令
    protected final static int confCmd =
        ByteBuffer.wrap("conf".getBytes()).getInt();
    /*
     * See <a href="{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands">
     * Zk Admin</a>. this link is for all the commands.
     */
    protected final static int consCmd =
        ByteBuffer.wrap("cons".getBytes()).getInt();
    /*
     * See <a href="{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands">
     * Zk Admin</a>. this link is for all the commands.
     */
    protected final static int crstCmd =
        ByteBuffer.wrap("crst".getBytes()).getInt();
    /*
     * See <a href="{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands">
     * Zk Admin</a>. this link is for all the commands.
     */
    protected final static int dumpCmd =
        ByteBuffer.wrap("dump".getBytes()).getInt();
    /*
     * See <a href="{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands">
     * Zk Admin</a>. this link is for all the commands.
     */
    protected final static int enviCmd =
        ByteBuffer.wrap("envi".getBytes()).getInt();
    /*
     * See <a href="{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands">
     * Zk Admin</a>. this link is for all the commands.
     */
    protected final static int getTraceMaskCmd =
        ByteBuffer.wrap("gtmk".getBytes()).getInt();
    /*
     * See <a href="{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands">
     * Zk Admin</a>. this link is for all the commands.
     */
    protected final static int ruokCmd =
        ByteBuffer.wrap("ruok".getBytes()).getInt();
    /*
     * See <a href="{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands">
     * Zk Admin</a>. this link is for all the commands.
     */
    protected final static int setTraceMaskCmd =
        ByteBuffer.wrap("stmk".getBytes()).getInt();
    /*
     * See <a href="{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands">
     * Zk Admin</a>. this link is for all the commands.
     */
    protected final static int srvrCmd =
        ByteBuffer.wrap("srvr".getBytes()).getInt();
    /*
     * See <a href="{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands">
     * Zk Admin</a>. this link is for all the commands.
     */
    protected final static int srstCmd =
        ByteBuffer.wrap("srst".getBytes()).getInt();
    /*
     * See <a href="{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands">
     * Zk Admin</a>. this link is for all the commands.
     */
    protected final static int statCmd =
        ByteBuffer.wrap("stat".getBytes()).getInt();
    /*
     * See <a href="{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands">
     * Zk Admin</a>. this link is for all the commands.
     */
    protected final static int wchcCmd =
        ByteBuffer.wrap("wchc".getBytes()).getInt();
    /*
     * See <a href="{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands">
     * Zk Admin</a>. this link is for all the commands.
     */
    protected final static int wchpCmd =
        ByteBuffer.wrap("wchp".getBytes()).getInt();
    /*
     * See <a href="{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands">
     * Zk Admin</a>. this link is for all the commands.
     */
    protected final static int wchsCmd =
        ByteBuffer.wrap("wchs".getBytes()).getInt();
    /*
     * See <a href="{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands">
     * Zk Admin</a>. this link is for all the commands.
     */
    protected final static int mntrCmd = ByteBuffer.wrap("mntr".getBytes())
            .getInt();
    /*
     * See <a href="{@docRoot}/../../../docs/zookeeperAdmin.html#sc_zkCommands">
     * Zk Admin</a>. this link is for all the commands.
     */
    protected final static int isroCmd = ByteBuffer.wrap("isro".getBytes())
            .getInt();
    // 存储CMD的整形值与String的键值对
    protected final static HashMap<Integer, String> cmd2String =
        new HashMap<Integer, String>();
    // specify all of the commands that are available
    static {
        cmd2String.put(confCmd, "conf");
        cmd2String.put(consCmd, "cons");
        cmd2String.put(crstCmd, "crst");
        cmd2String.put(dumpCmd, "dump");
        cmd2String.put(enviCmd, "envi");
        cmd2String.put(getTraceMaskCmd, "gtmk");
        cmd2String.put(ruokCmd, "ruok");
        cmd2String.put(setTraceMaskCmd, "stmk");
        cmd2String.put(srstCmd, "srst");
        cmd2String.put(srvrCmd, "srvr");
        cmd2String.put(statCmd, "stat");
        cmd2String.put(wchcCmd, "wchc");
        cmd2String.put(wchpCmd, "wchp");
        cmd2String.put(wchsCmd, "wchs");
        cmd2String.put(mntrCmd, "mntr");
        cmd2String.put(isroCmd, "isro");
    }
    /**
    * 服务器的统计数据
    **/
    // 创建连接的时间
    protected final Date established = new Date();
    // 接受的packet数量
    protected final AtomicLong packetsReceived = new AtomicLong();
    // 发送的packet数量
    protected final AtomicLong packetsSent = new AtomicLong();
    // 最小延迟
    protected long minLatency;
    // 最大延迟
    protected long maxLatency;
    // 最后操作类型
    protected String lastOp;
    // 最后的cxid
    protected long lastCxid;
    // 最后的zxid
    protected long lastZxid;
    // 最后的响应时间
    protected long lastResponseTime;
    // 最后的延迟
    protected long lastLatency;
    // 数量
    protected long count;
    // 总的延迟
    protected long totalLatency;
}
类的属性
说明:可以看到,ServerCnxn类维护了很多属性,主要是服务器的统计信息和和命令行信息。
3.4 核心函数分析
1. 抽象方法
// 获取会话超时时间
abstract int getSessionTimeout(); // 关闭
abstract void close(); // 发送响应
public abstract void sendResponse(ReplyHeader h, Record r, String tag)
throws IOException; /* notify the client the session is closing and close/cleanup socket */
// 关闭会话
abstract void sendCloseSession(); // 处理,Watcher接口中的方法
public abstract void process(WatchedEvent event); // 获取会话id
abstract long getSessionId(); // 设置会话id
abstract void setSessionId(long sessionId); // 设置缓冲
abstract void sendBuffer(ByteBuffer closeConn); // 允许接收
abstract void enableRecv(); // 不允许接收
abstract void disableRecv(); // 设置会话超时时间
abstract void setSessionTimeout(int sessionTimeout); // 获取服务器的统计数据
protected abstract ServerStats serverStats();
说明:以上的方法均为抽象方法,需要具体子类实现,如process方法是Watcher接口中的方法,在ServerCnxn中并未实现,需要具体子类实现。
2. 具体方法
/** auth info for the cnxn, returns an unmodifyable list */
// 获取认证信息,返回不可修改的列表
public List<Id> getAuthInfo() {
return Collections.unmodifiableList(authInfo);
} // 添加认证信息
public void addAuthInfo(Id id) {
if (authInfo.contains(id) == false) {
authInfo.add(id);
}
} // 移除认证信息
public boolean removeAuthInfo(Id id) {
return authInfo.remove(id);
} // 接收的packet
protected void packetReceived() {
incrPacketsReceived();
ServerStats serverStats = serverStats();
if (serverStats != null) {
serverStats().incrementPacketsReceived();
}
} // 发送的packet
protected void packetSent() {
incrPacketsSent();
ServerStats serverStats = serverStats();
if (serverStats != null) {
serverStats().incrementPacketsSent();
}
} // 重置统计数据
public synchronized void resetStats() {
packetsReceived.set(0);
packetsSent.set(0);
minLatency = Long.MAX_VALUE;
maxLatency = 0;
lastOp = "NA";
lastCxid = -1;
lastZxid = -1;
lastResponseTime = 0;
lastLatency = 0; count = 0;
totalLatency = 0;
} // 增加接收的packet数量
protected long incrPacketsReceived() {
return packetsReceived.incrementAndGet();
} // 增加outstandingRequest数量
protected void incrOutstandingRequests(RequestHeader h) {
} // 增加发送的packet数量
protected long incrPacketsSent() {
return packetsSent.incrementAndGet();
} // 更新响应的统计数据
protected synchronized void updateStatsForResponse(long cxid, long zxid,
String op, long start, long end)
{
// don't overwrite with "special" xids - we're interested
// in the clients last real operation
if (cxid >= 0) {
lastCxid = cxid;
}
lastZxid = zxid;
lastOp = op;
lastResponseTime = end;
long elapsed = end - start;
lastLatency = elapsed;
if (elapsed < minLatency) {
minLatency = elapsed;
}
if (elapsed > maxLatency) {
maxLatency = elapsed;
}
count++;
totalLatency += elapsed;
} public Date getEstablished() {
return (Date)established.clone();
} public abstract long getOutstandingRequests(); public long getPacketsReceived() {
return packetsReceived.longValue();
} public long getPacketsSent() {
return packetsSent.longValue();
} public synchronized long getMinLatency() {
return minLatency == Long.MAX_VALUE ? 0 : minLatency;
} public synchronized long getAvgLatency() {
return count == 0 ? 0 : totalLatency / count;
} public synchronized long getMaxLatency() {
return maxLatency;
} public synchronized String getLastOperation() {
return lastOp;
} public synchronized long getLastCxid() {
return lastCxid;
} public synchronized long getLastZxid() {
return lastZxid;
} public synchronized long getLastResponseTime() {
return lastResponseTime;
} public synchronized long getLastLatency() {
return lastLatency;
} /**
* Prints detailed stats information for the connection.
*
* @see dumpConnectionInfo(PrintWriter, boolean) for brief stats
*/
@Override
public String toString() {
StringWriter sw = new StringWriter();
PrintWriter pwriter = new PrintWriter(sw);
dumpConnectionInfo(pwriter, false);
pwriter.flush();
pwriter.close();
return sw.toString();
} public abstract InetSocketAddress getRemoteSocketAddress();
public abstract int getInterestOps(); /**
* Print information about the connection.
* @param brief iff true prints brief details, otw full detail
* @return information about this connection
*/
protected synchronized void
dumpConnectionInfo(PrintWriter pwriter, boolean brief) {
pwriter.print(" ");
pwriter.print(getRemoteSocketAddress());
pwriter.print("[");
int interestOps = getInterestOps();
pwriter.print(interestOps == 0 ? "0" : Integer.toHexString(interestOps));
pwriter.print("](queued=");
pwriter.print(getOutstandingRequests());
pwriter.print(",recved=");
pwriter.print(getPacketsReceived());
pwriter.print(",sent=");
pwriter.print(getPacketsSent()); if (!brief) {
long sessionId = getSessionId();
if (sessionId != 0) {
pwriter.print(",sid=0x");
pwriter.print(Long.toHexString(sessionId));
pwriter.print(",lop=");
pwriter.print(getLastOperation());
pwriter.print(",est=");
pwriter.print(getEstablished().getTime());
pwriter.print(",to=");
pwriter.print(getSessionTimeout());
long lastCxid = getLastCxid();
if (lastCxid >= 0) {
pwriter.print(",lcxid=0x");
pwriter.print(Long.toHexString(lastCxid));
}
pwriter.print(",lzxid=0x");
pwriter.print(Long.toHexString(getLastZxid()));
pwriter.print(",lresp=");
pwriter.print(getLastResponseTime());
pwriter.print(",llat=");
pwriter.print(getLastLatency());
pwriter.print(",minlat=");
pwriter.print(getMinLatency());
pwriter.print(",avglat=");
pwriter.print(getAvgLatency());
pwriter.print(",maxlat=");
pwriter.print(getMaxLatency());
}
}
pwriter.print(")");
}
具体方法
说明:ServerCnxn实现了Stats接口中的很多方法,其相对简单,不再累赘。
四、总结
本篇博文分析了ServerCnxn的源码,其是抽象类,定义了子类需要实现的方法,较为简单,也谢谢各位园友的观看~
【Zookeeper】源码分析之网络通信(一)的更多相关文章
- zookeeper源码分析之五服务端(集群leader)处理请求流程
		leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ... 
- zookeeper源码分析之四服务端(单机)处理请求流程
		上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ... 
- zookeeper源码分析之三客户端发送请求流程
		znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ... 
- Zookeeper 源码分析-启动
		Zookeeper 源码分析-启动 博客分类: Zookeeper 本文主要介绍了zookeeper启动的过程 运行zkServer.sh start命令可以启动zookeeper.入口的main ... 
- 【Zookeeper】源码分析之网络通信(二)
		一.前言 前面介绍了ServerCnxn,下面开始学习NIOServerCnxn. 二.NIOServerCnxn源码分析 2.1 类的继承关系 public class NIOServerCnxn ... 
- 【Zookeeper】源码分析之网络通信(三)
		一.前言 前面已经学习了NIOServerCnxn,接着继续学习NettyServerCnxn. 二.NettyServerCnxn源码分析 2.1 类的继承关系 public class Netty ... 
- 【Zookeeper】源码分析之网络通信(三)之NettyServerCnxn
		一.前言 前面已经学习了NIOServerCnxn,接着继续学习NettyServerCnxn. 二.NettyServerCnxn源码分析 2.1 类的继承关系 public class Netty ... 
- 【Zookeeper】源码分析之网络通信(二)之NIOServerCnxn
		一.前言 前面介绍了ServerCnxn,下面开始学习NIOServerCnxn. 二.NIOServerCnxn源码分析 2.1 类的继承关系 public class NIOServerCnxn ... 
- storm操作zookeeper源码分析-cluster.clj
		storm操作zookeeper的主要函数都定义在命名空间backtype.storm.cluster中(即cluster.clj文件中).backtype.storm.cluster定义了两个重要p ... 
随机推荐
- Cookie 简单使用记录浏览记录
			ItemsDAO.java package dao; import java.util.* ; import java.sql.* ; import util.DBHelper; import ent ... 
- 在MVC中添加拦截器实现登录后的权限验证
			1.新建一个类 (以下实现了打印日志功能) using System; using System.Collections.Generic; using System.Linq; using Syste ... 
- Python3基础 frozenset() 创建一个不可更改的集合
			镇场诗: 诚听如来语,顿舍世间名与利.愿做地藏徒,广演是经阎浮提. 愿尽吾所学,成就一良心博客.愿诸后来人,重现智慧清净体.-------------------------------------- ... 
- 内容页获取当前栏目的上一级栏目ID
			发现V9在列表页可以用$parentid 得到当前栏目的父级ID,但在内容页这个函数的值却为空了,需要按下面的写法才行, V9 在内容页获取当前栏目的上一级栏目ID {$CAT[parentid]} ... 
- JQuery flot API文档 中文版
			调用plot函数的方法如下: var plot = $.plot(placeholder, data, options) 其 中placeholder可以是JQuery的对象,DOM元素或者JQuer ... 
- Cisco VPN Client Error 56解决
			Cisco VPN Client Error 56解决 VPN Client报错 650) this.width=650;" style="width:575px;height:1 ... 
- Lazy.js : 让 JavaScript 变懒
			Lazy.js : 让 JavaScript 变懒 http://segmentfault.com/a/1190000000358463 
- Service介绍(MediaPlayer应用)
			一.Service介绍 Service类似于Windows中的服务,没有界面,只是在后台运行:而服务不能自己运行,而是需要调用Context.startService(Intent intent);或 ... 
- Treeview显示磁盘下的文件,并且可操作
			#region TreeView树形显示磁盘下文件夹 /// <summary> /// IconIndexs类 对应ImageList中5张图片的序列 /// </summary& ... 
- ASP.NET Zero--13.一个例子(6)商品分类管理-删除分类
			1.添加按钮 首先添加一个删除按钮,打开文件Index.js[..\MyCompanyName.AbpZeroTemplate.Web\Areas\Mpa\Views\Category\Index.j ... 
