tcp nio 远程主机强迫关闭了一个现有的连接
2014-05-10 16:27
357 查看
import java.io.IOException;
import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.SocketAddress; 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.util.Iterator; import java.util.Set; public class NIOServer implements Runnable { /*标识数字*/ private int flag = 0; /*缓冲区大小*/ private int BLOCK = 4096; /*接受数据缓冲区*/ private ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK); /*发送数据缓冲区*/ private ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK); private Selector selector; public NIOServer(int port){ try{ // 打开服务器套接字通道 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); // 服务器配置为非阻塞 serverSocketChannel.configureBlocking(false); // 检索与此通道关联的服务器套接字 ServerSocket serverSocket = serverSocketChannel.socket(); // 进行服务的绑定 serverSocket.bind(new InetSocketAddress(port)); // 通过open()方法找到Selector selector = Selector.open(); // 注册到selector,等待连接 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); System.out.println("Server Start----8888:"); }catch(Exception e){ e.printStackTrace(); } } // 监听 public void run() { try { while (true) { // 选择一组键,并且相应的通道已经打开 selector.select(); // 返回此选择器的已选择键集。 Set<SelectionKey> selectionKeys = selector.selectedKeys(); Iterator<SelectionKey> iterator = selectionKeys.iterator(); while (iterator.hasNext()) { SelectionKey selectionKey = iterator.next(); iterator.remove(); try{ handleKey(selectionKey); }catch(IOException e){ e.printStackTrace(); //selectionKey.cancel(); break; } } } } catch (Exception e) { e.printStackTrace(); } } // 处理请求 private void handleKey(SelectionKey selectionKey) throws IOException { // 接受请求 ServerSocketChannel server = null; SocketChannel client = null; SocketAddress clientaddr = null; String receiveText; String sendText; int count=0; // 测试此键的通道是否已准备好接受新的套接字连接。 if (selectionKey.isAcceptable()) { // 返回为之创建此键的通道。 server = (ServerSocketChannel) selectionKey.channel(); // 接受到此通道套接字的连接。 // 此方法返回的套接字通道(如果有)将处于阻塞模式。 client = server.accept(); clientaddr=client.socket().getRemoteSocketAddress(); System.out.printf("+++++++++++服务器端接受客户端[%s]连接!+++++++++++ \n",clientaddr); // 配置为非阻塞 client.configureBlocking(false); // 注册到selector,等待连接 client.register(selector, SelectionKey.OP_READ); } else if (selectionKey.isReadable()) { // 返回为之创建此键的通道。 client = (SocketChannel) selectionKey.channel(); clientaddr=client.socket().getRemoteSocketAddress(); //将缓冲区清空以备下次读取 receivebuffer.clear(); //读取服务器发送来的数据到缓冲区中 count = client.read(receivebuffer); if (count > 0) { receiveText = new String( receivebuffer.array(),0,count); System.out.printf("服务器端接受客户端[%s]数据:\n%s",clientaddr,receiveText); client.register(selector, SelectionKey.OP_WRITE); } } else if (selectionKey.isWritable()) { //将缓冲区清空以备下次写入 sendbuffer.clear(); // 返回为之创建此键的通道。 client = (SocketChannel) selectionKey.channel(); sendText="message from server--" + flag++; //向缓冲区中输入数据 sendbuffer.put(sendText.getBytes()); //将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位 sendbuffer.flip(); //输出到通道 client.write(sendbuffer); System.out.println("服务器端向客户端发送数据--:"+sendText); client.register(selector, SelectionKey.OP_READ); } } /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { // TODO Auto-generated method stub int port = 8888; NIOServer server = new NIOServer(port); server.run(); } }
上面是从网上摘录的Java NIO TCP 的一个server程序,用客户端的NIO TCP与之连接的时候,只要客户端断开连接,服务器端就会报出“远程主机强迫关闭了一个现有的连接”的错误,并且中断服务器端程序。经过查阅之后发现,得知“OP_READ
事件不仅仅只有可读时才触发,当channel中数据读完远程的另一端被关闭有一个错误的pending都会触发OP_READ事件"!
解决办法:在selectionKey.isReadable()中加入错误捕捉机制,即:
if (selectionKey.isReadable()) {
try {
// 返回为之创建此键的通道。
client = (SocketChannel) selectionKey.channel();
clientaddr=client.socket().getRemoteSocketAddress();
//将缓冲区清空以备下次读取
receivebuffer.clear();
//读取服务器发送来的数据到缓冲区中
count = client.read(receivebuffer);
if (count > 0) {
receiveText = new String( receivebuffer.array(),0,count);
System.out.printf("服务器端接受客户端[%s]数据:\n%s",clientaddr,receiveText);
client.register(selector, SelectionKey.OP_WRITE);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
selectionKey.cancel(); //取消selectionKey
}
就可以捕获异常,使服务器程序不会因为某一个客户端的断开而中断.
相关文章推荐
- Adb connection Error:远程主机强迫关闭了一个现有的连接
- 远程主机强迫关闭了一个现有的连接。请高手解答?
- android:Adb connection Error:远程主机强迫关闭了一个现有的连接
- HAProxy出现"远程主机强迫关闭了一个现有的连接 " 的错误及解决
- 【Python爬虫错误】ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接
- DeviceMonitor Adb connection Error:远程主机强迫关闭了一个现有的连接 解决方法
- Adb connection Error:远程主机强迫关闭了一个现有的连接
- Adb connection Error:远程主机强迫关闭了一个现有的连接
- android:Adb connection Error:远程主机强迫关闭了一个现有的连接
- 解决:Adb connection Error:远程主机强迫关闭了一个现有的连接
- DeviceMonitor Adb connection Error:远程主机强迫关闭了一个现有的连接 解决方法
- System.Data.SqlClient.SqlException: 在向服务器发送请求时发生传输级错误。 (provider: TCP 提供程序, error: 0 - 远程主机强迫关闭了一个现有的连接。)
- Adb connection Error:远程主机强迫关闭了一个现有的连接
- Adb connection Error:远程主机强迫关闭了一个现有的连接
- 在向服务器发送请求时发生传输级错误。 (provider: TCP 提供程序, error: 0 - 远程主机强迫关闭了一个现有的连接。)
- Adb connection Error:远程主机强迫关闭了一个现有的连接。 Connection attempts: 1 等adb报错方面的问题
- 远程主机强迫关闭了一个现有的连接(Maximum connection limit reached)
- Connection attempts: 11Adb connection Error:远程主机强迫关闭了一个现有的连接
- Adb connection Error:远程主机强迫关闭了一个现有的连接。
- Delphi scktsrvr 三层架构程序,解决“远程主机强迫关闭了一个现有的连接”(2)