2015-05-01 54 views
0

我在2個線程中使用一個SocketChannel,一個線程用於發送數據,另一個線程用於接收數據。Java NIO TCP超時問題

SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress(ip,port)); 
socketChannel.configureBlocking(false); 

線程1:使用上述的SocketChannel寫入數據

線程2:使用相同的SocketChannel讀取

我不使用任何選擇器與所述的SocketChannel如我所需的數據寫入和讀取異步(使用2個不同的線程)

問題:當連接丟失時,socketchannel.write()和socketchannel.read()操作不會引發任何錯誤。它只是阻止操作。

我需要檢測連接丟失。

我試過在線程2中使用心跳方法,但因爲讀取操作剛好阻塞,所以此方法無法工作。有沒有其他方法可以在不使用新線程中的心跳的情況下檢測連接丟失?

如果存在連接丟失,寫入/讀取時是否可能拋出錯誤?

在此先感謝。

編輯:

主題1:

public void run() { 
    socketChannel = SendAndReceivePacketUtil.createConnection(ip, port); 
    socketChannel.configureBlocking(false); 

    RecTask task = new RecTask(socketChannel); 
    Thread recThread = new Thread(task); 
    recThread.start(); 

    while(true) 
    { 
    byte[] data= getDataFromQueue(ip); 
    if(data!= null) { 
     //print(new String(data)); 
     sendPacket(data, socketChannel); 
    } 
    } 
} 

線程2:(RecTask)

public void run() { 
    while(true) { 
    byte[] data = receivePacket(socketChannel); 
    //print(new String(data)); 
    } 
} 

兩個線程1 & 2具有的try-catch-finally塊。最後關閉套接字通道。

了sendpacket:

int dataSent = 0; 
while (dataSent < data.length) { 
    long n = socketChannel.write(buf); 
     if (n < 0) { 
      throw new Exception(); 
     } 
     dataSent += (int) n; 
} 

receivePacket:

int dataRec = 0; 
byte[] data = new byte[length]; 
ByteBuffer buffer = ByteBuffer.wrap(data); 

while (dataRec < length) { 
    long n = socketChannel.read(buffer); 
    if (n < 0) { 
     throw new Exception(); 
    } 
    dataRec += (int) n; 
}  
return data; 

我發送和連續接收數據。但是一旦連接丟失,就不會打印,代碼就會卡住。它是一個android wifi直接應用程序。對於連接丟失情況,我只需關閉wifi模塊。

回答

1

我沒有使用任何選擇與一個SocketChannel,因爲我需要寫和讀(使用2個不同的線程)

這不是一個理由,以避免Selector.其實這是相當困難的是異步寫正確的非阻塞NIO代碼沒有Selector.

問題:當該連接丟失,socketchannel.write()和socketchannel.read()操作不會引發任何錯誤。它只是阻止操作。

不,它不。您處於非阻止模式。它要麼返回一個正整數,要麼是零,或者拋出一個異常。這是什麼?

我試過在線程2中使用心跳方法,但因爲讀取操作只是阻塞,所以這種方法不起作用。

讀取操作不會在非阻塞模式下阻塞。

是否有任何其他方式來檢測連接丟失,而不使用新的線程中的心跳?

檢測TCP連接丟失的唯一可靠方法是寫入連接。最終,這將引發IOException: connection reset.但連接丟失後也不會發生第一次,由於緩衝,重試等

是否有可能拋出錯誤而寫入/讀取如果連接丟失?

這就是發生了什麼事。

這個問題存在嚴重問題。您發佈的代碼不是真實的代碼,或者它不像您描述的那樣運行。您需要發佈更多內容,例如你的讀寫代碼。

+0

我已經用所需的代碼更新了問題。雖然我處於非阻塞模式,但在連接丟失時仍無法打印任何內容。此外代碼不會進入catch/finally塊,這就是爲什麼我假設代碼等待讀/寫操作。 –

+0

@Pulkit顯然,您的讀取和您的寫入都返回零,這會導致無限循環。這就是爲什麼你需要'select()''不使用'select()'來編寫非阻塞循環,這只是一個糟糕的技術,並且會浪費CPU的時間。 – EJP

+0

使用select可以使讀和寫異步嗎?另外,如果我將socketChannel.configureBloacking()更改爲true,那麼應該解決問題,對吧? –

0

您可以在套接字上查找啓用TCP-KEEP活動選項。在空閒連接上keep-alive消息被髮送並且對於TCP層的消息而言預期ACK。

如果TCP-KEEP活動失敗,則您的下一次讀/寫操作將導致錯誤(ECONNRESET),該錯誤可用作連接丟失的徵兆。

+1

兩個小時後。 – EJP

+0

我們能不能用更少的超時值設置套接字選項以保持活躍? – Prabhu

+0

據我所知,它依賴於操作系統。您必須在操作系統級別更改它 –