channelmedia disconnectedd 什么时候触发

> 博客详情
在netty框架中,类似org.jboss.netty.channel.SimpleChannelUpstreamHandler这样的关于NIO事件处理的抽象基类或接口都提供了channelClosed和channelDisconnected这两个接口,从字面意思分析,它们分别是“连接断开”和“连接关闭”的意思,语义非常相近,那么他们具体有什么区别的,笔者在org.jboss.netty.channel.socket.nio.NioWorker.java中找到了答案:
//netty version: 3.1.5GA
//file: org.jboss.netty.channel.socket.nio.NioWorker.java
//method: static void close(NioSocketChannel channel, ChannelFuture future)
//line: 581
future.setSuccess();
if (connected) {
fireChannelDisconnected(channel);
if (bound) {
fireChannelUnbound(channel);
cleanUpWriteBuffer(channel);
fireChannelClosed(channel);
我们可以看到,在上述代码中,在close channel的时候,会先判断当前channel是否处于connected状态,即是否已经成功地与远程地址建立了连接,如果是的话,就触发channelDisconnected事件;最后,再统一触发channelClosed事件。
也就是说,任何对NioWorker.close(NioSocketChannel channel, ChannelFuture future)方法的调用都会触发channelClosed事件,这些事件可能包括如下几种:
1. 已经与远程主机建立的连接,远程主机主动关闭连接,或者网络异常连接被断开的情况
2. 已经与远程主机建立的连接,本地客户机主动关闭连接的情况
3. 本地客户机在试图与远程主机建立连接时,遇到类似与connection refused这样的异常,未能连接成功时&
而只有当本地客户机已经成功的与远程主机建立连接(connected)时,连接断开的时候才会触发channelDisconnected事件,即对应上述的1和2两种情况。
上述猜想已经通过编写测试代码,模拟不同的情况得到了证实,如果还有不准确的地方,欢迎指正。
支付宝支付
微信扫码支付
打赏金额: ¥
已支付成功
打赏金额: ¥博客分类:
不喜欢写描述什么的,基本上使用步骤,注意事项都在代码注释中标明了,而相关的内容网上有很多,比自己的理解更好,所以自己对某个知识点的理解则都写在了为知笔记中。
1、服务端的编写
package com.netty.
import java.net.InetSocketA
import java.util.concurrent.ExecutorS
import java.util.concurrent.E
import org.jboss.netty.bootstrap.ServerB
import org.jboss.netty.buffer.ChannelB
import org.jboss.netty.buffer.ChannelB
import org.jboss.netty.channel.ChannelHandlerC
import org.jboss.netty.channel.ChannelP
import org.jboss.netty.channel.ChannelPipelineF
import org.jboss.netty.channel.ChannelStateE
import org.jboss.netty.channel.C
import org.jboss.netty.channel.ExceptionE
import org.jboss.netty.channel.MessageE
import org.jboss.netty.channel.SimpleChannelH
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelF
import org.jboss.netty.handler.codec.string.StringD
import org.jboss.netty.handler.codec.string.StringE
* @author Chalmers 日 下午6:49:57
public class NettyServer {
public static void main(String[] args) {
// 创建服务类对象
ServerBootstrap serverBootstrap = new ServerBootstrap();
// 创建两个线程池
// 简单来讲,就是boss监听端口,worker来监听selector(NIO里面的)
ExecutorService boss = Executors.newCachedThreadPool();
ExecutorService worker = Executors.newCachedThreadPool();
// 设置工厂,并且把两个线程池加入进去
// 经测试,该方法在netyy3.0中有效,5.0中没有
serverBootstrap.setFactory(new NioServerSocketChannelFactory(boss,
// 设置管道工厂
serverBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline channelPipeline = Channels.pipeline();
// 加上此行代码,在Handler中便可以直接获取字符串,而不用经过ChannelBuffer了
// 看源码可得,decoder用来处理上行数据
channelPipeline.addLast("decoder", new StringDecoder());
// encoder用来数据下行数据
channelPipeline.addLast("encoder", new StringEncoder());
* 经测试可得,decoder和encoder不能省去,而下面的可以省掉
channelPipeline.addLast("helloHandler", new ServerHandler());
return channelP
// 注意此行代码,在绑定时,一定要在工厂之后,否则就会报错
serverBootstrap.bind(new InetSocketAddress(9090));
System.out.println("start --& server");
class ServerHandler extends SimpleChannelHandler {
* 不管是否已经连接,都将执行
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e)
throws Exception {
super.channelClosed(ctx, e);
System.out.println("channelClosed");
* 当网络连接时执行
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
throws Exception {
super.channelConnected(ctx, e);
System.out.println("channelConnected");
* 只有当网络连接过,断开时才会执行
public void channelDisconnected(ChannelHandlerContext ctx,
ChannelStateEvent e) throws Exception {
super.channelDisconnected(ctx, e);
System.out.println("channelDisconnected");
* 捕获异常
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
throws Exception {
super.exceptionCaught(ctx, e);
System.out.println("exceptionCaught");
* 接收消息
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
throws Exception {
super.messageReceived(ctx, e);
System.out.println("messageReceived");
// 因为在设置管道工厂时,设置了StringDecode,所以在此时可以直接获得
// 但如果没有设置的话,可以通过以下方法
// ChannelBuffer message = (ChannelBuffer) e.getMessage();
// System.out.println(new String(message.array()));
System.out.println(e.getMessage());
* 发送消息
// ChannelBuffer copiedBuffer = ChannelBuffers.copiedBuffer("hi"
// .getBytes());
// ctx.getChannel().write(copiedBuffer);
// 因为在管道中设置了encoder,所以可以像读取一样,写成下面的形式
ctx.getChannel().write("hi");
2、客户端的编写
package com.netty.
import java.net.InetSocketA
import java.util.S
import java.util.concurrent.ExecutorS
import java.util.concurrent.E
import org.jboss.netty.bootstrap.ClientB
import org.jboss.netty.channel.C
import org.jboss.netty.channel.ChannelF
import org.jboss.netty.channel.ChannelHandlerC
import org.jboss.netty.channel.ChannelP
import org.jboss.netty.channel.ChannelPipelineF
import org.jboss.netty.channel.ChannelStateE
import org.jboss.netty.channel.C
import org.jboss.netty.channel.ExceptionE
import org.jboss.netty.channel.MessageE
import org.jboss.netty.channel.SimpleChannelH
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelF
import org.jboss.netty.handler.codec.string.StringD
import org.jboss.netty.handler.codec.string.StringE
* @author Chalmers 日 下午10:22:08
public class NettyClient {
private static ClientBootstrap clientB
public static void main(String[] args) {
// 获得客户端对象
clientBootstrap = new ClientBootstrap();
// 创建两个线程池
ExecutorService boss = Executors.newCachedThreadPool();
ExecutorService worker = Executors.newCachedThreadPool();
// 设置工厂,跟服务端一样
clientBootstrap.setFactory(new NioClientSocketChannelFactory(boss,
// 设置管道工厂
clientBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline channelPipeline = Channels.pipeline();
// 进行包装
channelPipeline.addLast("decoder", new StringDecoder());
channelPipeline.addLast("encoder", new StringEncoder());
channelPipeline.addLast("hiHandler", new ClientHandler());
return channelP
System.out.println("start --& client");
// 一定记住,这个地方用的是connect,而不是bind
ChannelFuture channelFuture = clientBootstrap
.connect(new InetSocketAddress("127.0.0.1", 9090));
// 可以冲future中获得channel
Channel channel = channelFuture.getChannel();
Scanner sc = new Scanner(System.in);
while (true) {
System.out.print("输入: ");
// 用获得channel进行输出
channel.write(sc.next());
class ClientHandler extends SimpleChannelHandler {
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e)
throws Exception {
super.channelClosed(ctx, e);
System.out.println("channelClosed");
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
throws Exception {
super.channelConnected(ctx, e);
System.out.println("channelConnected");
public void channelDisconnected(ChannelHandlerContext ctx,
ChannelStateEvent e) throws Exception {
super.channelDisconnected(ctx, e);
System.out.println("channelDisconnected");
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
throws Exception {
super.exceptionCaught(ctx, e);
System.out.println("exceptionCaught");
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
throws Exception {
super.messageReceived(ctx, e);
System.out.println("messageReceived");
System.out.println(e.getMessage());
MoonMonster
浏览: 17568 次
来自: 长沙
有些意思。加油
再看,发现中间有段体现自己好无知。
666,之前上网看socket的代码还奇怪loop是什么意思, ...
MoonMonster 写道BS_YG 写道涛霸可以啊,建议下 ...
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'博客分类:
Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。 如果需要客户端和服务器端沟通 分别都需要编写一个 实现了SimpleChannelHandler接口的类,其中类中需要重写的主要方法为 channelConnected() and channelOpen()
这两个方法为
当客户端链接到服务器端得时候和 客户端 channel被创建出来的时候所调用的 channelDisconnected and
channelClosed() 对应上面的两个方法 exceptionCaught 可以获得 对应handler端(服务器或客户端)的异常信息 messageReceived 每个 客户端 发送的信息后
将调用此方法 当编写完某端得程序后(客户端或服务器端) 将编写好的handler需要配置在 实现了ChannelPipelineFactory的类里,ChannelPipelineFactory中有一个需要实现的方法getPipeline将写好的handler配置到其中,在这个 工厂里 可能要添加很多东西 比如说 编解码器,心跳等。。。。 如需要自定义编解码器需要继承:LengthFieldBasedFrameDecoder(解码),OneToOneEncoder(编码) 编解码器(encode,decode) encode为
调用messageReceived 方法之后调用的方法,则decode方法为 messageReceived 之前调用的方法 ,用于处理自定义包协议的解析于编辑 心跳: 当客户端socket在非正常情况家掉线,如: 断网,断电等特殊问题的时候, 客户端的channel对象不会自动关闭,需要一直接收到客户端的消息,从而判断是否可以和对象构成通信。。 如果 发现客户端空闲时间过长则视为掉线 服务端handler代码如下 package com.djyou. import java.util.logging.L import org.jboss.netty.buffer.ChannelB import org.jboss.netty.channel.ChannelHandlerC import org.jboss.netty.channel.ChannelStateE import org.jboss.netty.channel.ChildChannelStateE import org.jboss.netty.channel.ExceptionE import org.jboss.netty.channel.MessageE import org.jboss.netty.channel.SimpleChannelH import org.jboss.netty.channel.group.ChannelG import org.jboss.netty.channel.group.DefaultChannelG public class ChatServerHandler extends SimpleChannelHandler{ public static final ChannelGroup channelGroup = new DefaultChannelGroup();
@Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
throws Exception {
System.out.println("进来一个"); } @Override public void channelDisconnected(ChannelHandlerContext ctx,
ChannelStateEvent e) throws Exception {
super.channelDisconnected(ctx, e); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
throws Exception {
Logger.getAnonymousLogger().info(e.getCause().getMessage());
ctx.getChannel().close();
// TODO Auto-generated method stub
//super.exceptionCaught(ctx, e); } @Override public void childChannelClosed(ChannelHandlerContext ctx,
ChildChannelStateEvent e) throws Exception {
super.childChannelClosed(ctx, e); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
throws Exception {
System.out.println(this.id++);
//google protocol解码后返回为 ChannelBuffer类型
if(!(e.getMessage() instanceof ChannelBuffer))
//获得 消息对象
ChannelBuffer channelBuffer = (ChannelBuffer)e.getMessage();
//MessageInfo info = Message.MessageInfo.newBuilder().mergeFrom(channelBuffer.copy().array()).build();
//写回给客户端
e.getChannel().write(channelBuffer);
} } pieplelineFactory里的代码为 package com.djyou. import static org.jboss.netty.channel.Channels.*; import org.jboss.netty.channel.ChannelP import org.jboss.netty.channel.ChannelPipelineF import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32FrameD import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldP import org.jboss.netty.handler.timeout.IdleStateH import org.jboss.netty.util.T public class ChatPipelineServerFactory implements ChannelPipelineFactory{ private T public ChatPipelineServerFactory(Timer timer){
this.timer = } @Override public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = pipeline();
//添加netty默认支持的 编解码器(可自动添加包头,并处理粘包问题) pipeline.addLast("frameDecoder", new ProtobufVarint32FrameDecoder());//对应 pipeline.addLast("frameEncoder", new ProtobufVarint32LengthFieldPrepender());//此对象为 netty默认支持protocolbuf的编解码器
pipeline.addLast("timeout", new IdleStateHandler(timer, 10, 10, 0));//此两项为添加心跳机制 10秒查看一次在线的客户端channel是否空闲,IdleStateHandler为netty jar包中提供的类
pipeline.addLast("hearbeat", new Heartbeat());//此类 实现了IdleStateAwareChannelHandler接口
//netty会定时扫描 空闲的channel
//pipeline.addLast("frameDecoder", new ProtobufDecoder(Message.MessageInfo.getDefaultInstance()));
//pipeline.addLast("frameEncoder", new ProtobufEncoder());//
pipeline.addLast("handler", new ChatServerHandler());//将编写好的服务器端的handler添加到这里
} } 心跳包的代码如下 import org.jboss.netty.channel.ChannelHandlerC import org.jboss.netty.handler.timeout.IdleS import org.jboss.netty.handler.timeout.IdleStateAwareChannelH import org.jboss.netty.handler.timeout.IdleStateE public class Heartbeat extends IdleStateAwareChannelHandler{ int i = 0; @Override public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e)
throws Exception {
// TODO Auto-generated method stub
super.channelIdle(ctx, e);
if(e.getState() == IdleState.WRITER_IDLE)
e.getChannel().close();
System.out.println("掉了。");
} } } 自定义解码器代码 package com.djyou. import org.jboss.netty.buffer.ChannelB import org.jboss.netty.channel.C import org.jboss.netty.channel.ChannelHandlerC import org.jboss.netty.handler.codec.frame.LengthFieldBasedFrameD public class Decode extends LengthFieldBasedFrameDecoder{ public Decode(int maxFrameLength, int lengthFieldOffset,
int lengthFieldLength) {
super(maxFrameLength, lengthFieldOffset, lengthFieldLength);
// TODO Auto-generated constructor stub } @Override protected Object decode(ChannelHandlerContext ctx, Channel channel,
ChannelBuffer buffer) throws Exception {
ChannelBuffer buffs = (ChannelBuffer)super.decode(ctx, channel, buffer);
} } 自定义编码器代码 package com.djyou. import org.jboss.netty.channel.C import org.jboss.netty.channel.ChannelHandlerC import org.jboss.netty.handler.codec.oneone.OneToOneE public class Encode extends OneToOneEncoder{ @Override protected Object encode(ChannelHandlerContext ctx, Channel channel,
Object msg) throws Exception {
// TODO Auto-generated method stub
} } 服务端启动代码 package com.djyou. import java.net.InetSocketA import java.util.concurrent.E import org.jboss.netty.bootstrap.ServerB import org.jboss.netty.channel.ChannelF import org.jboss.netty.channel.socket.nio.NioServerSocketChannelF import org.jboss.netty.util.HashedWheelT import org.jboss.netty.util.T public class ChatServer { public static void main(String[] args) {
ChannelFactory factory = new NioServerSocketChannelFactory(Executors
.newCachedThreadPool(), Executors.newCachedThreadPool(),
Runtime.getRuntime().availableProcessors() + 1);
Timer timer = new HashedWheelTimer();
ServerBootstrap bootstrap = new ServerBootstrap(factory);
bootstrap.setPipelineFactory(new ChatPipelineServerFactory(timer));
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.keepAlive", true);
bootstrap.setOption("reuseAddress", true);
bootstrap.bind(new InetSocketAddress(6666)); } } 客户端启动代码如下(除客户端启动代码意外 其余的东西都与服务器端一样 都需要编写对应的 编解码器,定时发送消息线程(10秒发个信息给服务端 确保channel不为空闲, 来对应心跳程序), 客户端的handler) package com.djyou. import java.io.BufferedR import java.io.InputStreamR import java.net.InetSocketA import java.util.concurrent.E import org.jboss.netty.bootstrap.ClientB import org.jboss.netty.buffer.ChannelB import org.jboss.netty.buffer.ChannelB import org.jboss.netty.channel.C import org.jboss.netty.channel.ChannelF import org.jboss.netty.channel.ChannelF import org.jboss.netty.channel.socket.nio.NioClientSocketChannelF import com.djyou.protoBufModel.M import com.djyou.protoBufModel.Message.MessageI public class ChatClient { public static void main(String[] args) throws Exception{
String host = "localhost";
int port = 6666;
// Configure the client.
ChannelFactory factory =
new NioClientSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool());
ClientBootstrap bootstrap = new ClientBootstrap(factory);
ChatPipelineClientFactory
cpcf = new ChatPipelineClientFactory();
bootstrap.setPipelineFactory(cpcf);
// Start the connection attempt.
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
// Wait until the connection attempt succeeds or fails.
Channel channel = future.awaitUninterruptibly().getChannel();
if (!future.isSuccess()) {
future.getCause().printStackTrace();
System.exit(0);
// Read commands from the stdin.
ChannelFuture lastWriteFuture =
BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); //
for (;;) { //
String line = in.readLine(); //
if (line == null) { //
//创建Builder
MessageInfo.Builder builder = MessageInfo.newBuilder();
builder.addBody(Message.Body.newBuilder().setKey("message").setValue("你在干什么?" + "/n").build());
//创建 赋值结束的 Build
并生成 MessageInfo对象
MessageInfo messageInfo = builder.build();
//将messageInfo转换为字节
byte[] messageByte = messageInfo.toByteArray();
//获得此对象的长度
ChannelBuffer channelBuffer = ChannelBuffers.buffer(messageByte.length);
//将 获得到的数组写入 channelBuffer中
channelBuffer.writeBytes(messageByte);
//发送到服务器端
for(int i = 0; i & 10;i++){
lastWriteFuture = channel.write(channelBuffer);
if (lastWriteFuture != null) {
lastWriteFuture.awaitUninterruptibly();
Thread.sleep(50000);
// Wait until all messages are flushed before closing the channel.
Thread.sleep(50000);
// Close the connection.
Make sure the close operation ends because
// all I/O operations are asynchronous in Netty.
channel.close().awaitUninterruptibly();
// We should shut down all thread pools here to exit normally.
// However, it is just fine to call System.exit(0) because we are
// finished with the business.
System.exit(0); } }
浏览 18651
浏览: 761353 次
来自: 武汉
prince4426 写道说的也太简单了吧。我还是没看懂你写个 ...
Shrio在线教程:http://www.sojson.com ...
不错,赞一个
写的不错,受用
可以发下源码吗
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'豆丁微信公众号
君,已阅读到文档的结尾了呢~~
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
netty的个人使用心得【转】
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='http://www.docin.com/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

我要回帖

更多关于 server disconnected 的文章

 

随机推荐