我目前正在调试两个通过TCP连接交换数据的Java应用程序。发送紧急数据后TCP连接重置
TCP客户端之一通过调用Socket#sendUrgentData(int)定期将紧急数据发送给另一个TCP服务器。本月18日试图发送紧急数据,TCP客户机抛出以下异常
java.io.IOException:BrokenPipe
at java.net.PlainSocketImpl.socketSendUrgentData(Native Method)
at java.net.PlainSocketImpl.sendUrgentData(PlainSocketImpl.java:541)
at java.net.Socket.sendUrgentData(Socket.java:927)
的TCP服务器抛出该异常
java.net.SocketException: Software caused connection abort: recv failed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
我相信例外是通过尝试写入引起/读到一个封闭的连接/插座。我不明白为什么连接或套接字在调用sendUrgentData()17次后关闭。我可以重复它,它总是在17次后发生。
如果我在Windows上运行客户端和服务器,则会出现问题。如果我在Solaris上运行客户端和服务器,则不会发生此问题。如果我在Solaris上运行客户端并在Windows上运行服务器,则会出现问题。如果我在Windows上运行客户机并在Solaris上运行服务器,则不会发生此问题。这让我觉得它可能与Windows有关?
使用Wireshark的我看到
--> = from TCP client to TCP server
<-- = from TCP server to TCP client
--> [PSH, ACK, URG] (Seq=1, Ack=1)
<-- [ACK] (Seq=1, Ack=2)
--> [PSH, ACK, URG] (Seq=2, Ack=1)
<-- [ACK] (Seq=1, Ack=3)
...
--> [PSH, ACK, URG] (Seq=17, Ack=1)
<-- [RST, ACK] (Seq=1, Ack=18)
我写了一些简单的测试类,这表明这一问题的连接以下网络通信。
TCPServer.java IP_ADDRESS端口
public class TCPServer
{
public static void main(String[] args) throws Exception
{
ServerSocket socket = new ServerSocket();
socket.bind(new InetSocketAddress(args[0], Integer.parseInt(args[1])));
System.out.println("BOUND/" + socket);
Socket connection = socket.accept();
System.out.println("CONNECTED/" + connection);
int b;
while ((b = connection.getInputStream().read()) != -1) {
System.out.println("READ byte: " + b);
}
System.out.println("CLOSING ..");
connection.close();
socket.close();
}
}
TCPClient.java IP_ADDRESS端口Interval_Between_Urgent_Data
public class TCPClient
{
public static void main(String[] args) throws Exception
{
final Socket socket = new Socket();
socket.connect(new InetSocketAddress(InetAddress.getByName(args[0]), Integer.parseInt(args[1])));
System.out.println("CONNECTED/"+socket);
Timer urgentDataTimer = new Timer(true);
urgentDataTimer.scheduleAtFixedRate(new TimerTask()
{
int n = 0;
public void run() {
try {
System.out.println("SENDING URGENT DATA ("+(++n)+") ..");
socket.sendUrgentData(1);
System.out.println("SENT URGENT DATA");
} catch (Exception e) {
e.printStackTrace();
}
}
}, 1000, Integer.parseInt(args[2]));
int b;
while ((b = socket.getInputStream().read()) != 1) {
System.out.println("READ byte: " + b);
}
System.out.println("CLOSING ..");
urgentDataTimer.cancel();
socket.close();
}
}
有人能解释这里发生了什么?
谢谢。
这是在Java中所有内联。 – EJP
感谢您的答案。由于[setOOBInline()](http://download.oracle.com/javase/6/docs/api/java/net/Socket.html#setOOBInline%28boolean%29))没有收到紧急数据设置(false)。紧急数据仅发送以防止在一段时间不活动后断开连接。设置[setKeepAlive](http://download.oracle.com/javase/6/docs/api/java/net/Socket.html#setKeepAlive%28boolean%29))将是一个更好的解决方案。 如果我设置了setOOBInline()(true),则不会发生断开连接并收到正确的字节。 – Stirls
为什么你使用紧急数据呢?只需发送应用程序级别的ping消息。紧急数据只有在您有大量排队等待处理(或发送)的数据时才有用,并且您希望立即通知另一端,而不是在处理完所有数据之后通知另一端。为了保持活力,情况并非如此;根据定义,您没有任何待处理的数据,并且可以正常发送应用程序级别的消息。由于RFC不匹配和平台问题,恕我直言,给出了紧急数据的问题,我很好地解决了这个问题。 –