一、前言

Java中直接使用socket进行通信的场景应该不是很多,在公司的一个项目中有这种需求,所以根据自己的理解和相关资料的参考,基于NIO 实现了一组工具类库,具体的协议还未定义,后续再整理

二、实现思路

包结构如下:

Listener: 事件监听接口

AcceptListener(请求事件接口),TCPServerProtocol实现类中当服务端接收到连接请求并成功建立通信之后通知注册的此事件集合;

ReadListener(读取事件接口),TCPProtocol实现类中读取接收到的信息完成之后通知注册的此事件集合;

SendListener(发送事件接口),TCPProtocol实现类中调用发送信息方法之后通知注册的此事件集合;

Protocol:TCP处理接口

TCPProtocol(读取、输出TCP处理接口),定义了NIO中关于输入、输出处理以及相关监听事件的维护

TCPServerProtocol(接收TCP请求处理接口),定义了NIO中TCP请求处理以及相关监听事件的维护

Util:辅助类

HelperUtil(一些基本操作工具类),定义获取KEY值,获取本地IP,核对结束帧等

SocketConfig(socket连接配置类),定义IP地址、端口、处理接口、是否自动重置等配置信息

SocketStat(socket连接状态管理类),管理socket的生命周期,提供socket控制方法

SocketLogicException(socket异常类),定义此类库中可能出现的异常

Socket:对外服务类

NSocketBlockClient(socket阻塞客户端类),提供阻塞的客户端实现

NSocketClient(socket非阻塞客户端类),提供非阻塞的客户端实现

NSocketService(socket非阻塞服务端类),提供非阻塞的服务端实现

SelectOptionListener(发送事件接口的实现),用于改变selector的interestOps为OP_WRITE

SocketClientTask(客户端线程任务),用于管理客户端的输入、输出事件以及异常处理

SocketServiceTask(服务端线程任务),用于管理服务端的输入、输出、请求事件以及异常处理

核心类图:

三、使用方式

(1) 通过实现AcceptListener、ReadListener、SendListener事件接口来注入发送、读取、接收业务

(2) 通过设置SocketConfig对象属性来进行SOCKET通信配置

(3) 通过NSocketBlockClient、NSocketClient、NSocketService对象来进行信息发送

服务端例子:

SocketConfig config=new SocketConfig(true, "10.33.6.178", 8899);
TCPServerProtocol protocol=new DefaultServerProtocol(new AcceptListener(){@Overridepublic void handleEvent(SocketStat socket) {socket.getConfig().getProtocol().addReadListener(new TestRead());}});NSocketService server=new NSocketService(config, protocol);

View Code

其中 TestRead 为实现ReadListener的类

public void handleEvent(byte[] message,TCPProtocol tcpProtocol) {System.out.println(new String(message,Charset.forName("GBK")));tcpProtocol.sendMessage("hello".getBytes(Charset.forName("GBK")));
}

View Code

非阻塞客户端例子:

SocketConfig config=new SocketConfig(true, "10.33.6.178", 8899);config.getProtocol().addReadListener(new ReadListener() {@Overridepublic void handleEvent(byte[] message, TCPProtocol tcpProtocol) {System.out.println("recive from server:"+ new String(message));                }});NSocketClient client=new NSocketClient(config);client.sendMessage("test nsocket".getBytes());

View Code

关于NIO处理的核心类:

public class DefaultServerProtocol implements TCPServerProtocol{ private LinkedList<AcceptListener> acceptList=new LinkedList<AcceptListener>();       public DefaultServerProtocol(AcceptListener... acceptColl){for(AcceptListener al:acceptColl){this.addAcceptListener(al);}}@Overridepublic SocketStat handleAccept(SelectionKey key) throws IOException {SocketChannel channel=((ServerSocketChannel)key.channel()).accept();  channel.configureBlocking(false);  Socket socket=channel.socket();SocketConfig config=new SocketConfig(false,socket.getInetAddress().getHostAddress(),socket.getPort(),this.createProtocol());        SocketStat stat=new SocketStat(config, key.selector(), channel);System.out.println("远程客户端地址:".concat(socket.getInetAddress().getHostAddress()));notifyAccept(stat);return stat;}@Overridepublic void addAcceptListener(AcceptListener al) {this.acceptList.add(al);       }@Overridepublic void notifyAccept(SocketStat socket) {for(AcceptListener al: acceptList){al.handleEvent(socket);}}/*** * 获取关于TCP 的读取和写入操作协议,可以override 返回自己的实现** @return      * @since  Ver 1.0*/public TCPProtocol createProtocol(){return new DefaultTCPProtocol();}
}

View Code

public class DefaultTCPProtocol implements TCPProtocol {       /**读取缓存区*/private ByteBuffer readBuff;        /**待发送消息队列*/protected Queue<ByteBuffer> messageQueue=new LinkedBlockingQueue<ByteBuffer>();/**锁*/private Object lockObje=new Object();/**读取监听*/private LinkedList<ReadListener> readList=new LinkedList<ReadListener>();/**发送监听*/private LinkedList<SendListener> sendList=new LinkedList<SendListener>();public DefaultTCPProtocol(ReadListener... readColl){        readBuff=ByteBuffer.allocate(1024);          for(ReadListener rl : readColl){this.addReadListener(rl);}}   @Overridepublic void handleRead(SelectionKey key) throws IOException {        SocketChannel clientChn=(SocketChannel)key.channel();ByteArrayOutputStream out=new ByteArrayOutputStream();try{   synchronized(this.readBuff){readBuff.clear();int bytesRead=clientChn.read(readBuff);    if(bytesRead==-1){throw new IOException("远程已关闭");}while(bytesRead>0){readBuff.flip();                out.write(readBuff.array(), 0, readBuff.limit());readBuff.clear();bytesRead=clientChn.read(readBuff);}            }                               key.interestOps(SelectionKey.OP_READ);notifyRead(out.toByteArray());}finally{out.close();}}       @Overridepublic  void handleWrite(SelectionKey key) throws IOException {SocketChannel clientChn=(SocketChannel)key.channel();ByteBuffer message=null;while(!messageQueue.isEmpty()){synchronized(lockObje){if(!messageQueue.isEmpty()){message=this.messageQueue.peek();                                        clientChn.write(message);if(message.hasRemaining()){                        break; }                    messageQueue.poll();}                                      }               }        key.interestOps(SelectionKey.OP_READ);}/*** * 发送消息(此时不是真正发送,而是放在一个待发送的队列中)** @param message 信息      * @since  Ver 1.0*/@Overridepublic void sendMessage(byte[] message) {        messageQueue.add(ByteBuffer.wrap(message));this.notifySend(message);}@Overridepublic void addReadListener(ReadListener rl) {        readList.add(rl);        }@Overridepublic void addSendListener(SendListener sl) {sendList.add(sl);}@Overridepublic void removeReadListener(ReadListener rl) {readList.remove(rl);}@Overridepublic void removeSendListener(SendListener rl) {sendList.remove(rl);}private void notifyRead(byte[] message) {               for(ReadListener rl : readList){rl.handleEvent(message,this);}}private void notifySend(byte[] message) {for(SendListener rl : sendList){rl.handleEvent(message);}}}

View Code

转载于:https://www.cnblogs.com/WGZ_Home/p/3400389.html

socket的NIO操作相关推荐

  1. java nio 传统标准io socket 和nio socket比较与学习

    在计算机系统中,最不可靠的就是网络请求,我们通过服务器端给客户端echo信息(客户端请求什么信息服务端就返回给客户端什么信息).比较两种socket io的优劣. 标准io socket:     服 ...

  2. 服务器可以pyqt显示吗,用pyqt+socket实现远程操作服务器的一个例子,PyQtsocket,方法,示例...

    @本文来源于公众号:csdn2299,喜欢可以关注公众号 程序员学府 这篇文章主要介绍了PyQt+socket实现远程操作服务器的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定 ...

  3. Java NIO操作Socket的用法

    我们都知道TCP是面向连接的传输层协议,一个socket必定会有绑定一个连接,在普通的BIO(阻塞式IO)中,需要有三次握手,然后一般的socket编程就是这样的形式. Socket服务器端流程如下: ...

  4. java nio close_wait_Java NIO 操作总结

    问题: 1.Java NIO 出现大量CLOSE_WAIT或TIME_WAIT的端口无法释放 CLOSE_WAIT: 参考:http://my.oschina.net/geecoodeer/blog/ ...

  5. SOCKET是调用操作系统通信服务的一种机制

    有没有SOCKET,网卡都会接收数据.网卡工作在数据链路层,它只认识链路上邻近的点.它甚至不认识它隔壁的隔壁,它又怎么可能知道传输层的信息呢(起点与终点,是传输层的信息)?...传输层的信息,只能由传 ...

  6. java 解锁关闭文件占用_程序员:Java文件锁定、解锁和其它NIO操作

    文件锁 java中i/o的文件锁定有两种:一种是独占锁,一种是共享锁. 共享锁既是共享读操作,但是只有一个可以进行写操作,共享锁防止其他正在运行的程序获取重复的独占锁,但是允许其他程序可以获取共享锁. ...

  7. io 错误: socket closed_Tomcat NIO(9)IO线程Overall流程和关键类

    在上一篇文章里我们主要介绍了 tomcat NIO 中 poller 线程的阻塞与唤醒,根据以前文章当 poller 线程监测到连接有数据可读事件的时候,会把原始 socket 的包装对象委托到 to ...

  8. 简易版聊天系统实现 Socket VS NIO两种实现方式

    1.Socket方式实现简易聊天效果 1.1服务端 Server.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 ...

  9. python socket mysql_5.Python操作MySQL,三层架构,Socket网络编程

    Python操作MySQL - MySQL之查询操作 - MySQL之插入数据 - MySQL之批量插入数据 - MySQL之删除数据 - MySQL之更新数据库 - MySQL之事务 - MySQL ...

最新文章

  1. pxeconfig 4.2.0 发布,PXE 首要启动设备
  2. 人脸识别技术在支付场景的机遇与挑战
  3. 《细胞》:打破百年生物学法则,记忆可以遗传给下一代,甚至可能跨越多代...
  4. C++ Set常用用法
  5. 操作系统:第二章 进程管理1 - 进程、线程
  6. C++11 右值引用与常量左值引用保存临时变量(函数返回值)的底层分析
  7. php用date语句获取时间,关于php date()函数获取时间的设置和使用方法
  8. 重构手法——提炼函数、搬移函数、以多态取代条件表达式
  9. 由m种数字组成的n位数有多少个
  10. iPhone Web App及优缺点【书摘】
  11. NOIP2017错题
  12. OverFeat 详解
  13. pt和字号的对应关系
  14. 在北邮 bbs上看到一个理解指针,指针数组不错的题目
  15. 直播第三方美颜sdk是什么?
  16. Oracle11安装教程
  17. 关于 石墨文档客户端 的案例分析
  18. Android Camera硬件结构组成(一)之 手机摄像头的组成结构和工作原理
  19. 用 justify-content 属性设置子元素两端对齐
  20. Java发送邮件中文乱码问题

热门文章

  1. codeforces——Little Pony and Expected Maximum
  2. Swift 结构体和类的最大区别
  3. 第三方控件radupload 使用方式以及报错处理
  4. rake -T 列出所有RAKE 命令.
  5. C/C++基本类型字节
  6. Android 动画(一)---布局动画
  7. Dlib学习笔记:dlib array2d与 OpenCV Mat互转
  8. flutter web:lottie jssdk报错处理
  9. yum报错-Network is unreachableError:
  10. 个人博客作业第三周--必应词典分析