一、前言

  前面已经分析了请求处理链中的多数类,接着继续分析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】源码分析之网络通信(一)的更多相关文章

  1. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  2. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  3. zookeeper源码分析之三客户端发送请求流程

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...

  4. Zookeeper 源码分析-启动

    Zookeeper 源码分析-启动 博客分类: Zookeeper   本文主要介绍了zookeeper启动的过程 运行zkServer.sh start命令可以启动zookeeper.入口的main ...

  5. 【Zookeeper】源码分析之网络通信(二)

    一.前言 前面介绍了ServerCnxn,下面开始学习NIOServerCnxn. 二.NIOServerCnxn源码分析 2.1 类的继承关系 public class NIOServerCnxn ...

  6. 【Zookeeper】源码分析之网络通信(三)

    一.前言 前面已经学习了NIOServerCnxn,接着继续学习NettyServerCnxn. 二.NettyServerCnxn源码分析 2.1 类的继承关系 public class Netty ...

  7. 【Zookeeper】源码分析之网络通信(三)之NettyServerCnxn

    一.前言 前面已经学习了NIOServerCnxn,接着继续学习NettyServerCnxn. 二.NettyServerCnxn源码分析 2.1 类的继承关系 public class Netty ...

  8. 【Zookeeper】源码分析之网络通信(二)之NIOServerCnxn

    一.前言 前面介绍了ServerCnxn,下面开始学习NIOServerCnxn. 二.NIOServerCnxn源码分析 2.1 类的继承关系 public class NIOServerCnxn ...

  9. storm操作zookeeper源码分析-cluster.clj

    storm操作zookeeper的主要函数都定义在命名空间backtype.storm.cluster中(即cluster.clj文件中).backtype.storm.cluster定义了两个重要p ...

随机推荐

  1. [Machine-Learning] 一个线性回归的简单例子

    这篇博客中做一个使用最小二乘法实现线性回归的简单例子. 代码来自<图解机器学习> 图3-2,使用MATLAB实现. 代码link 用到的matlab函数 由于以前对MATLAB也不是非常熟 ...

  2. docker网络访问(三)

    docker网络访问 ifconfig查看网卡,启动docker的时候,docker会帮我们创建一个docker0的网桥. 1.随机映射 docker run -P 2.指定映射 -p hostPor ...

  3. 一段神奇的代码-关于PHP字符变量奇怪现象的解释

    首先神奇的PHP是支持字符数据类型的,有同学就写了这样一段代码: for ($c = 'a'; $c <= 'z'; $c++) { echo $c . ' '; } 然而结果却不是他想要的a到 ...

  4. HDFS存储系统

    HDFS存储系统 一.基本概念 1.NameNode HDFS采用Master/Slave架构.namenode就是HDFS的Master架构.主要负责HDFS文件系统的管理工作,具体包括:名称空间( ...

  5. jQuery addClass removeClass toggleClass hasClass is(.class)用法

    jQuery addClass removeClass toggleClass hasClass is(.class)用法 <%@ page language="java" ...

  6. jQ小图标上下滑动特效

    嗯,又到了,夜静饥寒的时候,手指颤抖,回望去,屋内满是寂静,寥寥绰影,咳咳咳,想我程序员之路还没到终点...就...咳咳咳 好了日常神经结束,还要涂我的唇膏.还剩下,最后一章,js动画(四),明天放上 ...

  7. JDK源码分析-Integer

    Integer是平时开发中最常用的类之一,但是如果没有研究过源码很多特性和坑可能就不知道,下面深入源码来分析一下Integer的设计和实现. Integer: 继承结构: -java.lang.Obj ...

  8. Mac下安装cscope和ctags

    Mac下默认没有cscope和ctags,太不爽了,还好可以自己编译一个放进来 一.下载地址 cscope: http://downloads.sourceforge.net/project/csco ...

  9. requireJS的初步掌握

    前一段时间,因为一些事吧这个习惯落下了,现在争取重新捡起来. 最近开始自学requireJS,为了更好的掌握,所以写出一个自我理解的博客供参考. 分割线------------------------ ...

  10. C++的输入和输出

    C++是一种常用的编程语言.一个完整的程序至少要有一个输出,而我们也经常需要在程序内进行大量输入和输出.所以今天,我和大家谈一谈输入和输出. 1.cin和cout.可以连续输入,使用流(>> ...