我目前正在調試兩個通過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不匹配和平臺問題,恕我直言,給出了緊急數據的問題,我很好地解決了這個問題。 –