概述

先了解一下 netty 大概框架图 ,可以看到客户端的创建和服务端最大的区别 - 服务端传入两个 EventLoopGroup,客户端传入一个 EventLoopGroup - channel 的类型也不同,服务端传入的是 NioServerSocketChannel ,客户端传入的是 NioSocketChannel - 服务端存在 childHandler 的设置,客户端没有,

客户端连接过程 : - 和服务端一样先创建 EventLoopGroup (只有一个,内部多个保持多个EventLoop线程,执行处理事务) - connect 方法 ,和服务端一样,使用group里的EventLoop创建一个 channel ,然后注册到 select 中去(这个过程都在channel 中进行) - (异步执行)当连接不上就会交给 EventLoop线程中执行监听的任务。 - 而一旦监听到了就交给 channel 执行。 - selectKey 可以attack一个object,刚好可以用来放channel ,然后在某个线程监听到某个实现的时候再把 channel 拿出来用

源码分析

实际上客户端只有一个 Reactor . 那么重点的逻辑就到了 connect 那里

  1. /**
  2. * Connect a {@link Channel} to the remote peer.
  3. */
  4. public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
  5. if (remoteAddress == null) {
  6. throw new NullPointerException("remoteAddress");
  7. }
  8. validate();
  9. return doConnect(remoteAddress, localAddress);
  10. }
  11.  
  12. /**
  13. * @see {@link #connect()}
  14. */
  15. private ChannelFuture doConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) {
  16. //创建channel ,注册到 select , initAndRegister方法是父类的方法我们在分析服务端
  17. //的时候已经分析过了
  18. final ChannelFuture regFuture = initAndRegister();
  19. final Channel channel = regFuture.channel();
  20. //一开始就连接上了,
  21. if (regFuture.cause() != null) {
  22. return regFuture;
  23. }
  24.  
  25. final ChannelPromise promise = channel.newPromise();
  26. if (regFuture.isDone()) {
  27. //链路成功后,异步连接 TCP
  28. doConnect0(regFuture, channel, remoteAddress, localAddress, promise);
  29. } else {
  30. regFuture.addListener(new ChannelFutureListener() {
  31. @Override
  32. public void operationComplete(ChannelFuture future) throws Exception {
  33. doConnect0(regFuture, channel, remoteAddress, localAddress, promise);
  34. }
  35. });
  36. }
  37.  
  38. return promise;
  39. }
  40.  
  41. private static void doConnect0(
  42. final ChannelFuture regFuture, final Channel channel,
  43. final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {
  44.  
  45. // This method is invoked before channelRegistered() is triggered. Give user handlers a chance to set up
  46. // the pipeline in its channelRegistered() implementation.
  47. // 到了执行连接的操作就转到了Netty 的 NIO线程执行,此刻客户端返回,连接异步执行。
  48. channel.eventLoop().execute(new Runnable() {
  49. @Override
  50. public void run() {
  51. if (regFuture.isSuccess()) {
  52. if (localAddress == null) {
  53. //没传 localAddress 会传到 TailHandler的connect方法
  54. channel.connect(remoteAddress, promise);
  55. } else {
  56. //正常情况下到 HeaderHandler的connect 方法
  57. channel.connect(remoteAddress, localAddress, promise);
  58. }
  59. promise.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
  60. } else {
  61. promise.setFailure(regFuture.cause());
  62. }
  63. }
  64. });
  65. }
  1. 我们看一下 HeaderHandlerconnect 方法。
  1. @Override
  2. public void connect(
  3. ChannelHandlerContext ctx,
  4. SocketAddress remoteAddress, SocketAddress localAddress,
  5. ChannelPromise promise) throws Exception {
  6. //执行 HeaderHandler内的unsafe字段的 connect 方法
  7. unsafe.connect(remoteAddress, localAddress, promise);
  8. }

unsafe会执行AbstractNioChannel(这个类是NioServerSocketChannel和NioSocketChannel的共同父类)的connect 方法

  1. @Override
  2. public void connect(
  3. final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {
  4. if (!ensureOpen(promise)) {
  5. return;
  6. }
  7.  
  8. try {
  9. if (connectPromise != null) {
  10. throw new IllegalStateException("connection attempt already made");
  11. }
  12.  
  13. boolean wasActive = isActive();
  14. //doConnect 方法是个抽象方法
  15. if (doConnect(remoteAddress, localAddress)) {
  16. fulfillConnectPromise(promise, wasActive);
  17. } else {
  18. connectPromise = promise;
  19. requestedRemoteAddress = remoteAddress;
  20.  
  21. // Schedule connect timeout.
  22. int connectTimeoutMillis = config().getConnectTimeoutMillis();
  23. if (connectTimeoutMillis > 0) {
  24. connectTimeoutFuture = eventLoop().schedule(new Runnable() {
  25. @Override
  26. public void run() {
  27. ChannelPromise connectPromise = AbstractNioChannel.this.connectPromise;
  28. ConnectTimeoutException cause =
  29. new ConnectTimeoutException("connection timed out: " + remoteAddress);
  30. if (connectPromise != null && connectPromise.tryFailure(cause)) {
  31. close(voidPromise());
  32. }
  33. }
  34. }, connectTimeoutMillis, TimeUnit.MILLISECONDS);
  35. }
  36.  
  37. promise.addListener(new ChannelFutureListener() {
  38. @Override
  39. public void operationComplete(ChannelFuture future) throws Exception {
  40. if (future.isCancelled()) {
  41. if (connectTimeoutFuture != null) {
  42. connectTimeoutFuture.cancel(false);
  43. }
  44. connectPromise = null;
  45. close(voidPromise());
  46. }
  47. }
  48. });
  49. }
  50. } catch (Throwable t) {
  51. if (t instanceof ConnectException) {
  52. Throwable newT = new ConnectException(t.getMessage() + ": " + remoteAddress);
  53. newT.setStackTrace(t.getStackTrace());
  54. t = newT;
  55. }
  56. promise.tryFailure(t);
  57. closeIfClosed();
  58. }
  59. }

NioSocketChannel 的 doConnect 方法

  1. @Override
  2. protected boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
  3. if (localAddress != null) {
  4. javaChannel().socket().bind(localAddress);
  5. }
  6.  
  7. boolean success = false;
  8. try {
  9. boolean connected = javaChannel().connect(remoteAddress);
  10. if (!connected) {
  11. //如果绑定不成功,注册连接事件
  12. selectionKey().interestOps(SelectionKey.OP_CONNECT);
  13. }
  14. success = true;
  15. return connected;
  16. } finally {
  17. if (!success) {
  18. doClose();
  19. }
  20. }
  21. }

后续更新...

netty(二)---客户端连接的更多相关文章

  1. netty 处理客户端连接

    Netty如何处理连接事件 上文讲了Netty如何绑定端口,现在我们来阅读下netty如何处理connect事件.上文我们说了NioEventLoop启动后不断去调用select的事件,当客户端连接时 ...

  2. 【ActiveMQ】之安全机制(二)客户端连接安全

    配置完管控台的安全之后,我们还要配置客户端连接安全,否则大家都可以往MQ上发送消息,这样太危险! 根据官方文档,http://activemq.apache.org/security.html Act ...

  3. Netty 多客户端连接与通信

    实现场景: 聊天 服务端,客户端A,客户端B,客户端C.当客户端发送消息给服务端后,服务端在将这条消息广播个所有客户端户端A,客户端B,客户端C. 需求1: 客户端上线后,会通知所有客户端上线. 如客 ...

  4. Netty源码分析 (六)----- 客户端连接接入accept过程

    通读本文,你会了解到1.netty如何接受新的请求2.netty如何给新请求分配reactor线程3.netty如何给每个新连接增加ChannelHandler netty中的reactor线程 ne ...

  5. java socket通讯(二)处理多个客户端连接

    通过java socket通讯(一) 入门示例,就可以实现服务端和客户端的socket通讯,但是上一个例子只能实现一个服务端和一个客户端之间的通讯,如果有多个客户端连接服务端,则需要通过多线程技术来实 ...

  6. Memcache的客户端连接系列(二) Python

    关键词: Memcached   Python 客户端 声明:本文并非原创,转自华为云帮助中心的分布式缓存服务(Memcached)的用户指南.客户端连接方法通用,故摘抄过来分享给大家. Python ...

  7. 一个I/O线程可以并发处理N个客户端连接和读写操作 I/O复用模型 基于Buf操作NIO可以读取任意位置的数据 Channel中读取数据到Buffer中或将数据 Buffer 中写入到 Channel 事件驱动消息通知观察者模式

    Tomcat那些事儿 https://mp.weixin.qq.com/s?__biz=MzI3MTEwODc5Ng==&mid=2650860016&idx=2&sn=549 ...

  8. Redis基础知识之————如何处理客户端连接

    redis 连接建立 Redis Redis 通过监听一个 TCP 端口或者 Unix socket 的方式来接收来自客户端的连接,当一个连接建立后,Redis 内部会进行以下一些操作: 首先,客户端 ...

  9. PostgreSQL数据库服务端监听设置及客户端连接方法教程

    众所周知,PostgreSQL 是一个自由的对象-关系数据库服务器(数据库管理系统),是一个可以免费使用的开放源代码数据库系统.本文详细介绍了PostgreSQL数据库服务端监听设置及客户端连接方法, ...

随机推荐

  1. C++ 深拷贝实例-改变原生数组

    深拷贝 main.cpp #include <stdio.h> #include "IntArray.h" int main() { IntArray a(); ; i ...

  2. laravel框架实现发送邮件的功能

    1.在config 下的mail.php中配置(配置后面的两个就行了) 'from' => [ 'address' => env('MAIL_FROM_ADDRESS', '7623018 ...

  3. vue里不同数据的循环,其中的数组对象

    用产品的属性数据说明 页面里显示效果为:要把产品的属性显示到页面上,产品属性为后台自主上传产品的属性,产品的属性不同,所以需要把属性和属性值显示到页面上 产品属性数据为: properties: &q ...

  4. spring(三):BeanFactory

  5. Pacemaker+ISCSI实现Apache高可用-配置

    一.配置文件系统 任意节点用ISCSI的共享磁盘创建LVM node1 pvcreate /dev/sdb vgcreate my_vg /dev/sdb lvcreate -L 1G -n web_ ...

  6. DuPan不限速教程

    准备: 1.一个百度网盘链接 2.一个可以切换UA的浏览器, 手机版:via,极速浏览器,Kiwi浏览器(推荐)电脑版:未知 3.你的手和脑子

  7. 每天进步一点点------Xilinx IP 内核

    ISE 设计套件 11.1 版本中提供了众多全新的 IP 内核.数学函数:Multiply Adder v2.0 —— 执行两个操作数的乘法,并采用 XtremeDSP™ 解决方案切片将完全精确的乘积 ...

  8. JavaWeb项目忘记添加依赖

    有的时候我们建项目的时候忘记添加项目的依赖了,这里示范一个提示错误,就是 The superclass "javax.servlet.http.HttpServlet" was n ...

  9. js对象冒充实现的继承

    //人类 function Person(name) { this.name = name; this.showName = function () { console.log("my na ...

  10. poj 2195 Going Home(最小费用流)

    题目链接:http://poj.org/problem?id=2195 题目大意是给一张网格,网格中m代表人,h代表房子,网格中的房子和人数量相等,人可以向上向下走,每走1步花费加1,每个房子只能住一 ...