TCP protocol

对于以下异常的记录:

<pre name="code" class="java"><pre name="code" class="java">java.io.IOException: 远程主机强迫关闭了一个现有的连接。
	at sun.nio.ch.SocketDispatcher.read0(Native Method)
	at sun.nio.ch.SocketDispatcher.read(Unknown Source)
	at sun.nio.ch.IOUtil.readIntoNativeBuffer(Unknown Source)
	at sun.nio.ch.IOUtil.read(Unknown Source)
	at sun.nio.ch.SocketChannelImpl.read(Unknown Source)
	at mysite.socket.MyServer$1.run(MyServer.java:82)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)


一.以上异常的再现方法:

1.服务器开启socket监听,并通过nio的模式读,如下例:

int keysNum = selector.selectNow(); 
Iterator<SelectionKey> iterator= keysNum>0?selector.selectedKeys().iterator():null;
while(iterator!=null && iterator.hasNext() ){//while
	SelectionKey sk = iterator.next();
	iterator.remove();
	if(sk.isValid()){
		if(sk.isReadable()){
			SocketBufferHandler scBufferHandler = (SocketBufferHandler)sk.attachment();
			SocketChannel sc = scBufferHandler.getSocketChannel();
			ByteBuffer buffer = scBufferHandler.getBuffer();
			sc.read(buffer);//这个位置发生了异常
			if(!buffer.hasRemaining()){
				scBufferHandler.expand();
			}
			System.out.println(buffer);
		}
	}
}//while

2.客户端socket连接服务器,然后发送数据,发送完之后,客户端程度立刻停止,如下例:

ByteBuffer buf = ByteBuffer.allocate(100);
String str="hello world!!!";
buf.put(str.getBytes());
buf.flip();
for(int i=0;i<1000;i++){
	while(buf.hasRemaining()){
		socketChannel.write(buf);
	}
	buf.flip();
}
//这个close函数必须执行,否则会发生异常。
//socketChannel.close();

3.前面的循环会正常接收(具体循环到多少没有细算),但是至少最后一个会发生异常(大概)。


二.原因分析

常规的思想是认为:客户端发送完数据之后,不管客户端处于什么样的状态,包括异常状态,服务器都应该能正常接收到数据。但是上面的结果不如人意。

原因是什么???


三.nio循环读取

当执行socketChannel.close();方法时(即使客户端不执行write方法),虽然不报异常了,但是下面的方法竟然还是会循环。

if(sk.isReadable()){
		......
	}
这可能是因为当客户端执行close后,会发送FIN包,服务器端java认为这是isReadable的,于是就会陷入无限循环。下表对比了FIN包的特殊性。


mina的处理方法:



2017.08.28 =>









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值