mina中的发送延时
由于项目需要,用到了 mina 框架进行 tcp 通讯。我是初次接触 mina,于是从 Hello world 开始学习了 mina 。期间遇到了一个奇怪的发送数据的延迟问题,解决的过程是曲折的,但找出的原因却令我“吐血”(没真的吐……)。不管怎样,还是贴出来一下作反面案例,希望初次学习 mina 的时候能够绕过这个地雷。
|
public class HelloServer { public static void main(String[] args) { IoBuffer.setUseDirectBuffer(false); IoBuffer.setAllocator(new SimpleBufferAllocator()); IoAcceptor acceptor = new NioSocketAcceptor(); acceptor.getFilterChain().addLast("logger", new LoggingFilter()); acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory( Charset.forName("UTF-8")))); acceptor.getSessionConfig().setReadBufferSize(2048); acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10); acceptor.setHandler(new HelloHandler()); try { acceptor.bind(new InetSocketAddress(8800)); System.out.println("hello server is running!"); } catch (IOException e) { e.printStackTrace(); } } } |
|
public class HelloHandler extends IoHandlerAdapter { @Override public void sessionCreated(IoSession session) throws Exception { System.out.println("sessiong created ......"); } @Override public void sessionOpened(IoSession session) throws Exception { System.out.println("session opened ......"); } @Override public void sessionClosed(IoSession session) throws Exception { System.out.println("session closed ."); } @Override public void messageReceived(IoSession session, Object message) throws Exception { String msgText = message.toString(); System.out.println(getNow() + "message received!-- msg:" + msgText); } private String getNow(){ Date now = new Date(); DateFormat df = new SimpleDateFormat("[yyyy-MM-dd hh:mm:ss] "); return df.format(now); } @Override public void messageSent(IoSession session, Object message) throws Exception { String msgText = message.toString(); System.out.println("message sent!-- msg:" + msgText); } @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { System.out.println("exception occurred!!! -- " + cause.getMessage()); cause.printStackTrace(); session.close(false); } } |
|
public class HelloClient { public static void main(String[] args) { NioSocketConnector connector = new NioSocketConnector(); connector.setConnectTimeoutMillis(1000 * 15); connector.getFilterChain().addLast("logger", new LoggingFilter()); connector.getFilterChain().addLast( "codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset .forName("UTF-8")))); connector.setHandler(new HelloSender(new String[] { "Hello message 1 !", "Hello 2" })); try { ConnectFuture future = connector.connect(new InetSocketAddress( "127.0.0.1", 8800)); System.out.println("connect ..."); future.awaitUninterruptibly(); System.out.println("connect future awaitUniterruptibly ..."); IoSession session = future.getSession(); System.out.println("get session"); session.getCloseFuture().awaitUninterruptibly(); System.out.println("session close future awaitUniterruptibly ..."); connector.dispose(); } catch (Exception e) { System.out.println("error !!! --" + e.getMessage()); e.printStackTrace(); } } } |
|
public class HelloSender extends IoHandlerAdapter { private String[] msgArray; public HelloSender(String[] msgArray) { this.msgArray = msgArray; } @Override public void sessionOpened(IoSession session) throws Exception { SendMessage(session); session.close(false); System.out.println("client handler close session ......"); } private void SendMessage(IoSession session)throws Exception{ for (int i = 0; i < msgArray.length; i++) { WriteFuture wf = session.write(msgArray[i]); wf.addListener(new IoFutureListener<IoFuture>(){ public void operationComplete(IoFuture future) { System.out.println(getNow() + "futrue -- write completed!"); } }); System.out.println(getNow() + "--write msg " + i); Thread.sleep(3000); } System.out.println(getNow() + "send completed"); } private String getNow(){ Date now = new Date(); DateFormat df = new SimpleDateFormat("[yyyy-MM-dd hh:mm:ss] "); return df.format(now); } } |
|
// Now, we can write the message. First, create a future WriteFuture writeFuture = new DefaultWriteFuture(this); WriteRequest writeRequest = new DefaultWriteRequest(message, writeFuture, remoteAddress); // Then, get the chain and inject the WriteRequest into it IoFilterChain filterChain = getFilterChain(); filterChain.fireFilterWrite(writeRequest); |
|
s.getWriteRequestQueue().offer(s, writeRequest); if (!s.isWriteSuspended()) { s.getProcessor().flush(s); } |
((AbstractIoSession) session).getProcessor().flush(session);
connector.getSessionConfig().setTcpNoDelay(true);
运行 HelloClient ……
日志输出显示的结果还是一如既往。
NoDelay 是 TCP 层的一个选项,其指示是否将缓存区中的数据合并发送。但在此无论设置为 true 还是 false,都不影响测试的结果。
三、IoHandler 的问题
在进行了以上两方面的尝试后,将怀疑的目光转向了 HelloSender ,这是本例中的 IoHandler 的实现。
发送操作是在 HelloSender 的 sessionOpened 方法执行:
|
@Override public void sessionOpened(IoSession session) throws Exception { SendMessage(session); session.close(false); System.out.println("client handler close session ......"); } |
当 session 创建后,sessionOpened 便被执行,此时发送数据,并在发送完成后关闭会话的,然后,sessionOpened 方法返回。
仔细想想,似乎在 SendMessage 和 sessionOpened 方法返回之间有些问题:对 sessionOpened 的调用应该是建立连接和会话后初始化过程的一部分,而在初始化过程尚未返回的时候就对 IoSession 写入数据,这也许不是一个恰当的调用方式。也许正是这样,使得先后两次写入的数据都被保持在队列中,直到会话初始化完成后才被处理。在 sessionOpened 方法中创建一个新线程来执行 SendMessage 操作就能验证这一设想,于是 sessionOpened 方法改为如下:
|
@Override public void sessionOpened(IoSession session) throws Exception { final IoSession s = session; Thread thrd = new Thread(new Runnable() { public void run() { try { SendMessage(s); Thread.sleep(5000); s.close(false); } catch (Exception e) { System.out.println("Send message error!!!--" + e.getMessage()); e.printStackTrace(); } } }); thrd.start(); System.out.println("client handler close session ......"); } |
mina中的发送延时的更多相关文章
- 从mina中学习超时程序编写
从mina中学习超时程序编写 在很多情况下,程序需要使用计时器定,在指定的时间内检查连接过期.例如,要实现一个mqtt服务,为了保证QOS,在服务端发送消息后,需要等待客户端的ack,确保客户端接收到 ...
- mina中责任链模式的实现
一.mina的框架回顾 责任链模式在mina中有重要的作用,其中Filter机制就是基于责任链实现的. 从上图看到消息的接受从IoService层先经过Filter层过滤处理后最后交给IoHander ...
- spring boot:用rocketmq发送延时消息用来取消订单(spring boot 2.3.3)
一,为什么要用延时消息来取消订单? 1,为什么要取消订单 在电商的下单过程中,需要在生成订单时扣减库存, 但有可能发生这种情况:用户下了单,临时改变主意不再支付, 则订单不能无限期的保留,因为还要把占 ...
- php中PHPMailer发送带附件的电子邮件方法
摘要: 本文讲的是php中PHPMailer发送带附件的电子邮件方法, .首先到http://phpmailer.worxware.com/ 下载最新版本的程序包 2.下载完成后,找到class.ph ...
- JMeter 中实现发送Java请求
JMeter 中实现发送Java请求 1. 步骤1 新建JAVA项目 File -> New -> Java Project 如上图,填写Project Name,然后Next,打开以J ...
- ADO.NET 中可以发送包含多个SQL语句的批处理脚本到SQL Server,但是用MySQL的ODBC驱动不行
众所周知,我们在ADO.NET中可以使用NuGet包System.Data.SqlClient来操作SQL Server,并且ADO.NET是支持向SQL Server发送包含多个SQL语句的批处理脚 ...
- 解决c#所有单线程单元(STA)线程都应使用泵式等待基元(如 CoWaitForMultipleHandles),并在运行时间很长的操作过程中定期发送消息。 转载
最近做一个后来程序,启动了事务后有一段操作业务,当运行一段时间后,出现这个异常 CLR 无法从 COM 上下文 0x1b1c38 转换为 COM 上下文 0x1b1da8,这种状态已持续 60 秒.拥 ...
- 嵌入式流媒体音视频服务器EasyIPCamera中live555发送性能优化点
EasyIPCamera流媒体服务器 今年EasyDarwin团队在给国内某最大的金融安防公司做技术咨询的时候,开发了一款适用于嵌入式IPCamera.NVR的RTSP流媒体服务器:EasyIPCam ...
- 一种Cortex-M内核中的精确延时方法
本文介绍一种Cortex-M内核中的精确延时方法 前言 为什么要学习这种延时的方法? 很多时候我们跑操作系统,就一般会占用一个硬件定时器--SysTick,而我们一般操作系统的时钟节拍一般是设置100 ...
随机推荐
- 最简单的php验证码
<?php session_start(); // Settings: You can customize the captcha here $image_width = 120; $image ...
- linux c编程:管道
2在前面介绍过,进程之间交换信息的唯一途径就是传送打开的文件.可以经由fork或者exec来传送.这一章将介绍新的进程共享方式 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都 ...
- header函数使用
header('HTTP/1.1 200 OK'); //设置一个404头: header('HTTP/1.1 404 Not Found'); //设置地址被永久的重定向 header('HTTP/ ...
- Java mail 发送邮件 主题(标题)乱码
最近开发遇到Javamail 发送邮件标题乱码问题,腾讯.网易邮箱不会乱码,阿里邮箱 标题则会乱码.解决办法: String subject = MimeUtility.encodeWord(ma ...
- proguard 不混淆第三方jar包的问题
导入lib文件,并且用-dontwarn 和 keep class结合试试,例如: -libraryjars libs/log4j.jar -dontwarn org.apache.log4j.*-k ...
- SpringBoot学习笔记(3):静态资源处理
SpringBoot学习笔记(3):静态资源处理 在web开发中,静态资源的访问是必不可少的,如:Html.图片.js.css 等资源的访问. Spring Boot 对静态资源访问提供了很好的支持, ...
- HDU - 4965 Fast Matrix Calculation 【矩阵快速幂】
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=4965 题意 给出两个矩阵 一个A: n * k 一个B: k * n C = A * B M = (A ...
- mysql高可用研究(一) 主从+MHA架构
最近在研究mysql的高可用架构,自己想总结下常用的高可用方案都有哪些.有哪些优缺点以及应用的场景?搞得是头昏脑涨,天昏地暗,看了诸多资料,每次都觉得公说公有理婆说婆有理.其实嘛,大家说的都有一定的道 ...
- EntityFramework 学习 一 Stored Procedure
CREATE PROCEDURE [dbo].[GetCoursesByStudentId] -- Add the parameters for the stored procedure here @ ...
- Memory Layout of C Programs
Memory Layout of C Programs A typical memory representation of C program consists of following sec ...