我做的是服务端Socket,各位高手先看看代码吧
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.socket().bind(new InetSocketAddress(CommonBean.getSocketPort()));
serverChannel.configureBlocking(false);
Selector acceptSelector = SelectorProvider.provider().openSelector();
SelectionKey acceptKey = serverChannel.register(acceptSelector, SelectionKey.OP_ACCEPT);
int keysAdded = 0;
int k = 0;
while ((keysAdded = acceptSelector.select(1000 * 60)) > 0) {
Set readyKeys = acceptSelector.selectedKeys();
Iterator i = readyKeys.iterator();
while (i.hasNext()) {
SelectionKey selectionkey = (SelectionKey) i.next();
i.remove();
if (selectionkey != null) {
new Thread(new SocketThread(selectionkey)).start();
}
}
}
public class SocketThread extends Thread {
public SocketThread(SelectionKey selectionkey) {
this.selectionkey = selectionkey;
}
public void run() {
try {
ServerSocketChannel nextReady = (ServerSocketChannel) selectionkey.channel();
socketChannel = nextReady.accept();
if (socketChannel != null){
socketLog.info("[ "+socketChannel.socket().getInetAddress().getHostAddress()+" ] Thread started....");
processRequest();
socketLog.info("[ "+socketChannel.socket().getInetAddress().getHostAddress()+" ] Thread ended...");
}
} catch (Exception e) {
socketLog.error(e.getMessage(), e);
}
}
private void processRequest() {
try {
while (true) {
ByteBuffer tempMsgID = ByteBuffer.allocate(4);
tempMsgID.clear();
socketChannel.read(tempMsgID);
tempMsgID.flip();
if (tempMsgID.limit() == 0) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
socketChannel.socket().close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
我把服务端建立socket通讯的主要代码都摘取出来了,麻烦各位高手分析一下问题的原因以及解决的办法,我的问题如下:
一、我在前面已经设置了serverChannel.configureBlocking(false);为非阻塞模式,为什么当我调用socketChannel.read(tempMsgID);的时候,read依然用阻塞的方式去读取数据呢?
二、测试时候发现,如果客户端拔网线或者拔电源时,服务端不知道客户端退出,所以read就永远死在程序里了,当前的这个线程就一直存在了,我现在想设置read的timeout,比如说不管客户端异常退出还是由于其他原因,只要read超过3分钟,我就将当前这个socket关闭退出,在网上找了好久,没找到如何能设置socketChannel的timeout方法,不知道是我没找到,socketChannel就无法设置超时,如果无法设置超时,那么我的这个问题有没有别的解决办法呢?
三、我在网上查找socketChannel的timeout的方法时,发现socket可以设置超时,所以想到将socket从socketChannel中提取出来,用socket的方式进行读取,例如:socketChannel.socket().getinputstream();虽然说新版的NIO和旧版的纯socket相结合使用有点不伦不类,但是数据真的能正常收取,并且设置timeout也按时退出了,但是这种方式有新的问题,当我用20台客户端并发访问服务端的时候,运行一段时间就报too many open files的错误了,我检查程序了,我在最后的finally模块中,确实每次都将inputstream和socket全都close()了,但是依然解决不了too many open files异常,不知道该怎么办了。
希望NIO方面的高手来指点一下,NIO我接触的不多,现在这几个问题实在是没有能力解决了。
呵呵,我也是提供一种思路。
首先你的程序问题还是很多的,建议你看看O'Reilly的java nio这本书。
还有就是nio陷阱很多,建议还是使用开源的nio库如mina来使用网络通信。下面在说说你提到的几个问题。
1.serverChannel.configureBlocking(false);是吧监听端口的socket设置成了非阻塞,并没有把accept的socket调用.configureBlocking(false);所以read肯定是阻塞的。
2.nio的超时是通过记录各个事件如read write的时间点通过轮询来实现的,否则就不是nio非阻塞通信了。
3.too many open file可能是打开的socket超过单个进程打开文件数造成的,在linux下面默认是1024个。