一、前言

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(){
@Override
public void handleEvent(SocketStat socket) {
socket.getConfig().getProtocol().addReadListener(new TestRead());
} });
NSocketService server=new NSocketService(config, protocol);

其中 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")));
}

非阻塞客户端例子:

SocketConfig config=new SocketConfig(true, "10.33.6.178", 8899);
config.getProtocol().addReadListener(new ReadListener() { @Override
public 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());

关于NIO处理的核心类:

public class DefaultServerProtocol implements TCPServerProtocol{ 

    private LinkedList<AcceptListener> acceptList=new LinkedList<AcceptListener>();       

    public DefaultServerProtocol(AcceptListener... acceptColl){
for(AcceptListener al:acceptColl){
this.addAcceptListener(al);
}
} @Override
public 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;
} @Override
public void addAcceptListener(AcceptListener al) {
this.acceptList.add(al);
} @Override
public void notifyAccept(SocketStat socket) {
for(AcceptListener al: acceptList){
al.handleEvent(socket);
}
} /**
*
* 获取关于TCP 的读取和写入操作协议,可以override 返回自己的实现
*
* @return
* @since Ver 1.0
*/
public TCPProtocol createProtocol(){
return new DefaultTCPProtocol();
}
}
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);
}
} @Override
public 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();
}
} @Override
public 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
*/
@Override
public void sendMessage(byte[] message) {
messageQueue.add(ByteBuffer.wrap(message));
this.notifySend(message);
} @Override
public void addReadListener(ReadListener rl) {
readList.add(rl);
} @Override
public void addSendListener(SendListener sl) {
sendList.add(sl);
} @Override
public void removeReadListener(ReadListener rl) { readList.remove(rl); } @Override
public 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);
} } }

socket的NIO操作的更多相关文章

  1. Java NIO 操作总结

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

  2. Java Socket(3): NIO

    NIO采取通道(Channel)和缓冲区(Buffer)来传输和保存数据,它是非阻塞式的I/O,即在等待连接.读写数据(这些都是在一线程以客户端的程序中会阻塞线程的操作)的时候,程序也可以做其他事情, ...

  3. day 4 Socket 和 NIO Netty

    Scoket通信--------这是一个例子,可以在这个例子的基础上进行相应的拓展,核心也是在多线程任务上进行修改 package cn.itcast.bigdata.socket; import j ...

  4. [ PyQt入门教程 ] PyQt+socket实现远程操作服务器

    来需求了..干活啦.. 需求内容 部分时候由于缓存刷新.验证码显示不出来或者浏览器打不开或者打开速度很慢等原因,导致部分测试同事不想使用浏览器登录服务器执行命令.期望有小工具可以替代登录浏览器的操作, ...

  5. Socket网络通信——IO、NIO、AIO介绍以及区别

    一 基本概念 Socket又称"套接字",应用程序通常通过"套接字"向网路发出请求或者应答网络请求. Socket和ServerSocket类位于java.ne ...

  6. NIO【同步非阻塞io模型】关于 NIO socket 的详细总结【Java客户端+Java服务端 + 业务层】【可以客户端间发消息】

    1.前言 以前使用 websocket来实现双向通信,如今深入了解了 NIO 同步非阻塞io模型 , 优势是 处理效率很高,吞吐量巨大,能很快处理大文件,不仅可以 做 文件io操作, 还可以做sock ...

  7. 用socket操作redis

    代码: $cmd = "*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n"; // set foo bar $socket = socke ...

  8. Java I/O之NIO Socket

    PS:本文简单介绍下旧I/O和NIO下的Socket通讯,仅以UDP来示例. TCP/IP协议 首先简单回顾下TCP/IP协议 Application:应用程序:Socket:套接字:Host:主机: ...

  9. NIO vs. BIO

    性能测试 BIO -- Blocking IO 即阻塞式IO NIO -- Non-Blocking IO, 即非阻塞式IO或异步IO 性能 -- 所谓的性能是指服务器响应客户端的能力,对于服务器我们 ...

随机推荐

  1. iPhone丢失后通过iccid找回流程

    切记,丢失IPHONE第一时间要去补卡,免得小偷刷机用你的卡激活,这样你查到的号码只会是你自己的号码找iphone有2个方法:ICCID和维修换机.两者之间没任何直接联系,请不要混淆!下面是总体流程图 ...

  2. [liu yanling]测试用例设计综合策略

    Myers提出了使用各种测试方法的综合策略: 1)    在任何情况下都必须使用边界值分析方法,经验表明用这种方法设计出测试用例发现程序错误的能力最强. 2)    必要时用等价类划分方法补充一些测试 ...

  3. sunlime操作

    ctrl+p 查找文件  @进行符号查找ctrl+h 替换文件 选中字符以后多次按 ctrl+D 跳过则按 ctrl+Kctrl+shift+d 复制多行alt+f3 多选 ctrl+shift+p ...

  4. HW3.4

    import java.util.Scanner; public class Solution { public static void main(String[] args) { Scanner i ...

  5. POJ1006 - Biorhythms(中国剩余定理)

    题目大意 略...有中文... 题解 就是解同余方程组 x≡(p-d)(mod 23) x≡(e-d)(mod 28) x≡(i-d)(mod 33) 最简单的中国剩余定理应用.... 代码: #in ...

  6. poj1149--PIGS(最大流)

    题意: 有m个猪圈 每个猪圈有不同数量的猪 [0, 1000]有n个顾客 每个顾客需要Bi头猪 有Ai个钥匙 能打开Ai个不同的猪圈顾客按顺序来买猪 只能买他有钥匙的猪 买完之后 这几个猪圈的猪可以相 ...

  7. 最简单实现跨域的方法:用 Nginx 反向代理

    本文作者: 伯乐在线 - 良少 .未经作者许可,禁止转载!欢迎加入伯乐在线 专栏作者. 什么是跨域 跨域,指的是浏览器不能执行其他网站的脚本.它是由浏览器的同源策略造成的,是浏览器对javascrip ...

  8. A Tour of Go Short variable declarations

    Inside a function, the := short assignment statement can be used in place of a var declaration with ...

  9. 导入excel数据

    前提条件:先要安装好EXCEL软件. 程序中经常要用到导入excel数据的功能.其实通过ole操作excel就简单的几行代码,但记性不好,经常要用经常要找, 还是作篇笔记吧. var ExcelApp ...

  10. 大型网站都喜欢把js写在html中的真正原因

    相信经常观察大站的朋友都会发现,他们都把CSS写在HTML页面里,一个页面的或者多个页面的背景图片,都集成到一张图片里,他们有的JS文件,也写到页面里了……也许你会迷惑,现在到处讲页面的优化,不都是要 ...