tcp nio 远程主机强迫关闭了一个现有的连接
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 {
<span class="hljs-comment">/*标识数字*/</span>
<span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> flag = <span class="hljs-number">0</span>;
<span class="hljs-comment">/*缓冲区大小*/</span>
<span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> BLOCK = <span class="hljs-number">4096</span>;
<span class="hljs-comment">/*接受数据缓冲区*/</span>
<span class="hljs-keyword">private</span> ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK);
<span class="hljs-comment">/*发送数据缓冲区*/</span>
<span class="hljs-keyword">private</span> ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK);
<span class="hljs-keyword">private</span> Selector selector;
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">NIOServer</span><span class="hljs-params">(<span class="hljs-keyword">int</span> port)</span></span>{
<span class="hljs-keyword">try</span>{
<span class="hljs-comment">// 打开服务器套接字通道</span>
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
<span class="hljs-comment">// 服务器配置为非阻塞</span>
serverSocketChannel.configureBlocking(<span class="hljs-keyword">false</span>);
<span class="hljs-comment">// 检索与此通道关联的服务器套接字</span>
ServerSocket serverSocket = serverSocketChannel.socket();
<span class="hljs-comment">// 进行服务的绑定</span>
serverSocket.bind(<span class="hljs-keyword">new</span> InetSocketAddress(port));
<span class="hljs-comment">// 通过open()方法找到Selector</span>
selector = Selector.open();
<span class="hljs-comment">// 注册到selector,等待连接</span>
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println(<span class="hljs-string">"Server Start----8888:"</span>);
}<span class="hljs-keyword">catch</span>(Exception e){
e.printStackTrace();
}
}
<span class="hljs-comment">// 监听</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span> </span>{
<span class="hljs-keyword">try</span> {
<span class="hljs-keyword">while</span> (<span class="hljs-keyword">true</span>) {
<span class="hljs-comment">// 选择一组键,并且相应的通道已经打开</span>
selector.select();
<span class="hljs-comment">// 返回此选择器的已选择键集。</span>
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
<span class="hljs-keyword">while</span> (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
iterator.remove();
<span class="hljs-keyword">try</span>{
handleKey(selectionKey);
}<span class="hljs-keyword">catch</span>(IOException e){
e.printStackTrace();
<span class="hljs-comment">//selectionKey.cancel();</span>
<span class="hljs-keyword">break</span>;
}
}
}
} <span class="hljs-keyword">catch</span> (Exception e) {
e.printStackTrace();
}
}
<span class="hljs-comment">// 处理请求</span>
<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">handleKey</span><span class="hljs-params">(SelectionKey selectionKey)</span> <span class="hljs-keyword">throws</span> IOException </span>{
<span class="hljs-comment">// 接受请求</span>
ServerSocketChannel server = <span class="hljs-keyword">null</span>;
SocketChannel client = <span class="hljs-keyword">null</span>;
SocketAddress clientaddr = <span class="hljs-keyword">null</span>;
String receiveText;
String sendText;
<span class="hljs-keyword">int</span> count=<span class="hljs-number">0</span>;
<span class="hljs-comment">// 测试此键的通道是否已准备好接受新的套接字连接。</span>
<span class="hljs-keyword">if</span> (selectionKey.isAcceptable()) {
<span class="hljs-comment">// 返回为之创建此键的通道。</span>
server = (ServerSocketChannel) selectionKey.channel();
<span class="hljs-comment">// 接受到此通道套接字的连接。</span>
<span class="hljs-comment">// 此方法返回的套接字通道(如果有)将处于阻塞模式。</span>
client = server.accept();
clientaddr=client.socket().getRemoteSocketAddress();
System.out.printf(<span class="hljs-string">"+++++++++++服务器端接受客户端[%s]连接!+++++++++++ \n"</span>,clientaddr);
<span class="hljs-comment">// 配置为非阻塞</span>
client.configureBlocking(<span class="hljs-keyword">false</span>);
<span class="hljs-comment">// 注册到selector,等待连接</span>
client.register(selector, SelectionKey.OP_READ);
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (selectionKey.isReadable()) {
<span class="hljs-comment">// 返回为之创建此键的通道。</span>
client = (SocketChannel) selectionKey.channel();
clientaddr=client.socket().getRemoteSocketAddress();
<span class="hljs-comment">//将缓冲区清空以备下次读取</span>
receivebuffer.clear();
<span class="hljs-comment">//读取服务器发送来的数据到缓冲区中</span>
count = client.read(receivebuffer);
<span class="hljs-keyword">if</span> (count > <span class="hljs-number">0</span>) {
receiveText = <span class="hljs-keyword">new</span> String( receivebuffer.array(),<span class="hljs-number">0</span>,count);
System.out.printf(<span class="hljs-string">"服务器端接受客户端[%s]数据:\n%s"</span>,clientaddr,receiveText);
client.register(selector, SelectionKey.OP_WRITE);
}
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (selectionKey.isWritable()) {
<span class="hljs-comment">//将缓冲区清空以备下次写入</span>
sendbuffer.clear();
<span class="hljs-comment">// 返回为之创建此键的通道。</span>
client = (SocketChannel) selectionKey.channel();
sendText=<span class="hljs-string">"message from server--"</span> + flag++;
<span class="hljs-comment">//向缓冲区中输入数据</span>
sendbuffer.put(sendText.getBytes());
<span class="hljs-comment">//将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位</span>
sendbuffer.flip();
<span class="hljs-comment">//输出到通道</span>
client.write(sendbuffer);
System.out.println(<span class="hljs-string">"服务器端向客户端发送数据--:"</span>+sendText);
client.register(selector, SelectionKey.OP_READ);
}
}
<span class="hljs-comment">/**
* <span class="hljs-doctag">@param</span> args
* <span class="hljs-doctag">@throws</span> IOException
*/</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> IOException </span>{
<span class="hljs-comment">// TODO Auto-generated method stub</span>
<span class="hljs-keyword">int</span> port = <span class="hljs-number">8888</span>;
NIOServer server = <span class="hljs-keyword">new</span> 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
}
就可以捕获异常,使服务器程序不会因为某一个客户端的断开而中断.
tcp nio 远程主机强迫关闭了一个现有的连接的更多相关文章
- 在向服务器发送请求时发生传输级错误。 (provider: TCP 提供程序, error: 0 - 远程主机强迫关闭了一个现有的连接。)
用VS2005+SQLSERVER2008开发C/S的程序,程序上线运行一段时间之后发现在某些功能偶尔出现如下的错误: 在向服务器发送请求时发生传输级错误. (provider: TCP 提供程序, ...
- Netty学习4—NIO服务端报错:远程主机强迫关闭了一个现有的连接
1 发现问题 NIO编程中服务端会出现报错 Exception in thread "main" java.io.IOException: 远程主机强迫关闭了一个现有的连接. at ...
- System.Data.SqlClient.SqlException: 在向服务器发送请求时发生传输级错误。 (provider: TCP 提供程序, error: 0 - 远程主机强迫关闭了一个现有的连接。) .
今天使用sql server 2008 R2管理器,进行SQL查询时,频率非常高的报错: System.Data.SqlClient.SqlException: 在向服务器发送请求时发生传输级错误. ...
- eclipse连接远程Hadoop报错,Caused by: java.io.IOException: 远程主机强迫关闭了一个现有的连接。
eclipse连接远程Hadoop报错,Caused by: java.io.IOException: 远程主机强迫关闭了一个现有的连接.全部报错信息如下: Exception in thread & ...
- HAProxy出现"远程主机强迫关闭了一个现有的连接 " 的错误及解决
使用haproxy作为sql server 的负载均衡器. 使用了文档中的示例配置项: timeout client 50s timeout server 50s 采用这个配置项,有时会 ...
- Redis的Unable to connect to Redis和java.io.IOException: 远程主机强迫关闭了一个现有的连接问题的解决
学习项目xhr系统用到springboot + vue(https://github.com/lenve/vhr),文档中要求使用到RabbitMQ,但是从我搭建开发环境来看,是否配置Rabbit ...
- Adb connection Error:远程主机强迫关闭了一个现有的连接
在用手机调试程序时,有时会出现“Adb connection Error:远程主机强迫关闭了一个现有的连接”的错误. 出现这种错误时,可以按照以下步骤解决: (1)运行cmd.exe,并将目录CD到\ ...
- Adb connection Error:远程主机强迫关闭了一个现有的连接 解决方法
用真机调试程序的时候,eclipse 的 Console 总是出现如下的错误"Adb connection Error:远程主机强迫关闭了一个现有的连接". 问题出现的原因:这是 ...
- 解决WCF大数据量传输 ,System.Net.Sockets.SocketException: 远程主机强迫关闭了一个现有的连接
开发中所用的数据需要通过WCF进行数据传输,结果就遇到了WCF大量传输问题 也就是提示System.Net.Sockets.SocketException: 远程主机强迫关闭了一个现有的连接 网上解决 ...
随机推荐
- tp5.0初入
1.目录结构 |-application 应用目录 是整个网站的核心 |---|---index 前台目录 |---|-----|---controller 控制器 |---|-----|---mod ...
- 转-Spark编程指南
Spark 编程指南 概述 Spark 依赖 初始化 Spark 使用 Shell 弹性分布式数据集 (RDDs) 并行集合 外部 Datasets(数据集) RDD 操作 基础 传递 Functio ...
- 选择排序算法Java实现
一. 算法描述 选择排序:比如在一个长度为N的无序数组中,在第一趟遍历N个数据,找出其中最小的数值与第一个元素交换,第二趟遍历剩下的N-1个数据,找出其中最小的数值与第二个元素交换......第N-1 ...
- Jongmah CodeForces - 1110D
传送门 题意:你有n个数字,范围[1, m],你可以选择其中的三个数字构成一个三元组,但是这三个数字必须是连续的或者相同的,每个数字只能用一次,问这n个数字最多构成多少个三元组? 题解:三个一模一样的 ...
- sql查询平均下单时间
SQL查询订单平均审核时长 今天在写一个sql,需求是算一个订单在执行状态中的各个节点的时长 比如在订单中,状态0为开始接单,状态3为已经审核,那么现在需要计算每个客服的平均审核时长 像图中所示:这个 ...
- 浅谈XX系统跨平台迁移(测试环境)
一 概述 XX系统目前运行在XX-A的云平台上,计划将其迁移至XX-B的云平台. XX系统是java开发,中间组件涉及nginx+keepalived实现各个业务系统之间的高可用,kafka,zook ...
- Atlantis HDU - 1542
Problem Description There are several ancient Greek texts that contain descriptions of the fabled is ...
- IIS发布错误记录
1.HTTP 错误 500.19 - Internal Server Error 无法访问请求的页面,因为该页的相关配置数据无效. 详细错误信息模块 IIS Web Core 通知 BeginRequ ...
- 11.1,nginx集群概念
集群介绍 为什么要用集群
- 关于update 表名 set 字段1 = 值1 and 字段2 = 值2的执行结果说明
技术交流群: 233513714 如果执行了以下的语句,则brand等于‘OPPO’条件所对应的数据不会做改变,但是sequence_brand列除brand = 'OPPO'之外的所有数据都会变为0 ...