求一个NIO实现的长连接池 想学习学习,大侠们抛一个上来吗 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 没太看懂你要的究竟是个啥,NIO的主要是实现非阻塞网络通讯,从而可以使得单线程可以同时支持大量长连接,从而大大降低维护长连接的开销。跟池并没有直接关系。为啥会需要有池的概念?要池啥子东西? 供你参考吧:import java.io.ByteArrayOutputStream;import java.io.IOException;import java.net.InetSocketAddress;import java.net.ServerSocket;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Date;public class EchoServer { private static int SOCKET_NUM = 55555; private DateFormat dateFormatter = new SimpleDateFormat("yyyyMMdd HH:mm:ss"); /** * @param args */ public static void main(String[] args) { new EchoServer().start(); } public void start() { try { Selector selector = bindServer(); // 绑定服务端口,并定义一个事件选择器对象记录套接字通道的事件 /* 通过此循环来遍例事件 */ while (true) { log("Waiting events."); int n = selector.select(); // 查询事件如果一个事件都没有,这里就会阻塞 log("Got events: " + n); ByteBuffer echoBuffer = ByteBuffer.allocate(50); // 定义一个byte缓冲区来存储收发的数据 /* 循环遍例所有产生的事件 */ for (SelectionKey key : selector.selectedKeys()) { SocketChannel sc; selector.selectedKeys().remove(key); // 将本此事件从迭带器中删除 /* 如果产生的事件为接受客户端连接(当有客户端连接服务器的时候产生) */ if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) { ServerSocketChannel subssc = (ServerSocketChannel) key.channel(); // 定义一个服务器socket通道 sc = subssc.accept(); // 将临时socket对象实例化为接收到的客户端的socket sc.configureBlocking(false); // 将客户端的socket设置为异步 sc.register(selector, SelectionKey.OP_READ); // 将客户端的socket的读取事件注册到事件选择器中 System.out.println("Got new client:" + sc); } /* 如果产生的事件为读取数据(当已连接的客户端向服务器发送数据的时候产生) */ else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) { sc = (SocketChannel) key.channel(); // 临时socket对象实例化为产生本事件的socket ByteArrayOutputStream bos = new ByteArrayOutputStream(); // 定义一个用于存储byte数据的流对象,存储全部信息 echoBuffer.clear(); // 先将客户端的数据清空 try { // 循环读取所有客户端数据到byte缓冲区中,当有数据的时候read函数返回数据长度 // NIO会自动的将缓冲区一次容纳不下的自动分段 int readInt = 0; // 为读取到数据的长度 while ((readInt = sc.read(echoBuffer)) > 0) { // 如果获得数据长度比缓冲区大小小的话 if (readInt < echoBuffer.capacity()) { byte[] readByte = new byte[readInt]; // 建立一个临时byte数组,将齐长度设为获取的数据的长度 // 循环向此临时数组中添加数据 for (int i = 0; i < readInt; i++) { readByte[i] = echoBuffer.get(i); } bos.write(readByte); // 将此数据存入byte流中 } // 否则就是获得数据长度等于缓冲区大小 else { bos.write(echoBuffer.array()); // 将读取到的数据写入到byte流对象中 } } // 当循环结束时byte流中已经存储了客户端发送的所有byte数据 log("Recive msg: " + new String(bos.toByteArray())); } catch (Exception e) { e.printStackTrace(); // 当客户端在读取数据操作执行之前断开连接会产生异常信息 key.cancel(); // 将本socket的事件在选择器中删除 break; } writeBack(sc, bos.toByteArray()); // 向客户端写入收到的数据 } } } } catch (Exception e) { e.printStackTrace(); } } /** * 绑定服务端口,初始化整个服务 * @throws IOException */ private Selector bindServer() throws IOException { log("Start binding server socket:" + SOCKET_NUM); Selector selector = Selector.open(); // 定义一个事件选择器对象记录套接字通道的事件 ServerSocketChannel ssc = ServerSocketChannel.open(); // 定义一个异步服务器socket对象 ssc.configureBlocking(false);// 将此socket对象设置为异步 ServerSocket ss = ssc.socket(); // 定义服务器socket对象-用来指定异步socket的监听端口等信息 InetSocketAddress address = new InetSocketAddress(SOCKET_NUM); // 定义存放监听端口的对象 ss.bind(address); // 将服务器与这个端口绑定 ssc.register(selector, SelectionKey.OP_ACCEPT); // 将异步的服务器socket对象的接受客户端连接事件注册到selector对象内 log("Binded socket at:" + SOCKET_NUM); return selector; } private boolean writeBack(SocketChannel sc, byte[] b) { ByteBuffer echoBuffer = ByteBuffer.allocate(b.length); // 建立这个byte对象的ByteBuffer echoBuffer.put(b); // 将数据存入 echoBuffer.flip(); // 将缓冲区复位以便于进行其他读写操作 try { // 向客户端写入数据,数据为接受到数据 sc.write(echoBuffer); } catch (IOException e) { e.printStackTrace(); return false; } System.out.println("Msg echo back: " + new String(echoBuffer.array())); return true; } private void log(Object msg) { System.out.println("SERVER [" + dateFormatter.format(new Date()) + "]: " + msg); }} for (SelectionKey key : selector.selectedKeys()) { SocketChannel sc; selector.selectedKeys().remove(key); selector.selectedKeys()返回的集是线程安全的么?可以在没有同步的情况下在遍历中移除? 非线程安全,但本来这个例子就是单线程管理多TCP连接,所以不用担心这个问题。 很少有人直接用NIO做东西的,除非你学习用;考虑用个异步通信框架 比如 mina java循环基础 为什么Random random = new Random();这个会报错?求解。 EOFException异常问题----java读写游戏中的地图 一些小问题 java中一个严肃的问题? 如何设置Label的背景色为透明 新手提问,java中判断网络连接是否正常 急 请问如何去掉JTree中结点左边的连线? 请教关于jpcap的问题 ServerSocket端连接多个客户端为什么做成死循环 poi解析excel到mysql JAVA线程问题
跟池并没有直接关系。为啥会需要有池的概念?要池啥子东西?
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;public class EchoServer { private static int SOCKET_NUM = 55555; private DateFormat dateFormatter = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
/**
* @param args
*/
public static void main(String[] args) {
new EchoServer().start();
} public void start() {
try {
Selector selector = bindServer(); // 绑定服务端口,并定义一个事件选择器对象记录套接字通道的事件
/* 通过此循环来遍例事件 */
while (true) {
log("Waiting events.");
int n = selector.select(); // 查询事件如果一个事件都没有,这里就会阻塞
log("Got events: " + n);
ByteBuffer echoBuffer = ByteBuffer.allocate(50); // 定义一个byte缓冲区来存储收发的数据 /* 循环遍例所有产生的事件 */
for (SelectionKey key : selector.selectedKeys()) {
SocketChannel sc;
selector.selectedKeys().remove(key); // 将本此事件从迭带器中删除
/* 如果产生的事件为接受客户端连接(当有客户端连接服务器的时候产生) */
if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) {
ServerSocketChannel subssc = (ServerSocketChannel) key.channel(); // 定义一个服务器socket通道
sc = subssc.accept(); // 将临时socket对象实例化为接收到的客户端的socket
sc.configureBlocking(false); // 将客户端的socket设置为异步
sc.register(selector, SelectionKey.OP_READ); // 将客户端的socket的读取事件注册到事件选择器中
System.out.println("Got new client:" + sc);
}
/* 如果产生的事件为读取数据(当已连接的客户端向服务器发送数据的时候产生) */
else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {
sc = (SocketChannel) key.channel(); // 临时socket对象实例化为产生本事件的socket
ByteArrayOutputStream bos = new ByteArrayOutputStream(); // 定义一个用于存储byte数据的流对象,存储全部信息
echoBuffer.clear(); // 先将客户端的数据清空
try {
// 循环读取所有客户端数据到byte缓冲区中,当有数据的时候read函数返回数据长度
// NIO会自动的将缓冲区一次容纳不下的自动分段
int readInt = 0; // 为读取到数据的长度
while ((readInt = sc.read(echoBuffer)) > 0) {
// 如果获得数据长度比缓冲区大小小的话
if (readInt < echoBuffer.capacity()) {
byte[] readByte = new byte[readInt]; // 建立一个临时byte数组,将齐长度设为获取的数据的长度
// 循环向此临时数组中添加数据
for (int i = 0; i < readInt; i++) {
readByte[i] = echoBuffer.get(i);
}
bos.write(readByte); // 将此数据存入byte流中
}
// 否则就是获得数据长度等于缓冲区大小
else {
bos.write(echoBuffer.array()); // 将读取到的数据写入到byte流对象中
}
}
// 当循环结束时byte流中已经存储了客户端发送的所有byte数据
log("Recive msg: " + new String(bos.toByteArray()));
} catch (Exception e) {
e.printStackTrace(); // 当客户端在读取数据操作执行之前断开连接会产生异常信息
key.cancel(); // 将本socket的事件在选择器中删除
break;
}
writeBack(sc, bos.toByteArray()); // 向客户端写入收到的数据
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
} /**
* 绑定服务端口,初始化整个服务
* @throws IOException
*/
private Selector bindServer() throws IOException {
log("Start binding server socket:" + SOCKET_NUM);
Selector selector = Selector.open(); // 定义一个事件选择器对象记录套接字通道的事件 ServerSocketChannel ssc = ServerSocketChannel.open(); // 定义一个异步服务器socket对象 ssc.configureBlocking(false);// 将此socket对象设置为异步 ServerSocket ss = ssc.socket(); // 定义服务器socket对象-用来指定异步socket的监听端口等信息 InetSocketAddress address = new InetSocketAddress(SOCKET_NUM); // 定义存放监听端口的对象 ss.bind(address); // 将服务器与这个端口绑定 ssc.register(selector, SelectionKey.OP_ACCEPT); // 将异步的服务器socket对象的接受客户端连接事件注册到selector对象内 log("Binded socket at:" + SOCKET_NUM);
return selector;
}
private boolean writeBack(SocketChannel sc, byte[] b) {
ByteBuffer echoBuffer = ByteBuffer.allocate(b.length); // 建立这个byte对象的ByteBuffer
echoBuffer.put(b); // 将数据存入
echoBuffer.flip(); // 将缓冲区复位以便于进行其他读写操作
try {
// 向客户端写入数据,数据为接受到数据
sc.write(echoBuffer);
} catch (IOException e) {
e.printStackTrace();
return false;
}
System.out.println("Msg echo back: " + new String(echoBuffer.array()));
return true;
} private void log(Object msg) {
System.out.println("SERVER [" + dateFormatter.format(new Date()) + "]: " + msg);
}
}
for (SelectionKey key : selector.selectedKeys()) {
SocketChannel sc;
selector.selectedKeys().remove(key);
selector.selectedKeys()返回的集是线程安全的么?可以在没有同步的情况下在遍历中移除?
考虑用个异步通信框架 比如 mina