2011-11-30 28 views
0

我在Windows 7 x64上。我正在編寫一個服務器,它爲每個傳入連接打開一個線程 - 線程從連接的輸入流中讀取數據。如果套接字關閉(),read()會阻塞並拋出一個異常。它不 - 只返回-1。如果我沒有關閉客戶端的連接 - 只是讓客戶端終止 - 我得到的連接重置被重視 - 但是如果我關閉()來自客戶端的連接(或者僅僅是客戶端的輸出流)read()在服務器線程中不拋出 - 只返回-1。該docs是很清楚這個:當我關閉客戶端的套接字時,socket.getInputSteam.read()不會拋出

公共無效的close() 拋出IOException異常

Closes this socket. 

Any thread currently blocked in an I/O operation upon this socket will throw a SocketException. 

幫助

工作代碼:

服務器:

import java.io.IOException; 
import java.io.InputStream; 
import java.net.InetAddress; 
import java.net.ServerSocket; 
import java.net.Socket; 
import java.net.SocketException; 
import java.util.logging.Level; 
import java.util.logging.Logger; 

public class CloseTest { 
    private int port; 

    public CloseTest(int port) { 
     this.port = port; 
    } 

    void base_station_activate() { 
     ServerSocket baseStationListeningSocket=null; 
     try { 
      baseStationListeningSocket = new ServerSocket(this.port, 1, InetAddress.getByName("127.0.0.1")); 
     } catch (IOException ex) { 
     } 

     main_server: while (true) { 
      try { 
       Socket clientSocket = baseStationListeningSocket.accept(); 
       BaseStationClientHandler ch = new BaseStationClientHandler(clientSocket); 
       Thread myThread = new Thread(ch); 
       myThread.start(); 
      } catch (IOException ex) { 
       System.exit(1); 
      } // main_server 
      finally { 
//     baseStationListeningSocket.close() 
      } 
     } 
    } 
    public static void main(String args[]){ 
      CloseTest bs = new CloseTest(8082); 
      bs.base_station_activate(); 
     } 
    public class BaseStationClientHandler implements Runnable { 
     private final Socket clientSocket; 

     private BaseStationClientHandler(Socket clientSocket) { 
      this.clientSocket = clientSocket; 
     } 

     public void run() { 
      String debug_message = null; 
      try { 
       InputStream in = clientSocket.getInputStream(); 
       // read message and respond 
       String s = ""; 
       char x; 
       int r; 
       server: while (true) { 
        try { 
         while ((r = in.read()) != (int) '%') { 
          if (r == -1) { 
           debug_message = "Stream/socket .closed() - exception not thrown (WHYYYYY ????) by client"; 
           System.out.println(debug_message); 
           break server; 
          } 
          x = (char) r; 
          s += x; 
         } 
         System.out.println(s); 
        } catch (SocketException socketException) { 
         System.out.println(socketException.getLocalizedMessage()); // if connection reset (but not if Stream/socket .closed()) read throws !!!!! 
         debug_message = "socket_reset"; 
         break server; 
        } 
        s = ""; 
       } //server 
      } catch (IOException ex) { 
       System.out.println("IOexception in client handler - check if thrown by read"); 
      } finally { 
       try { 
        clientSocket.close(); 
       } catch (IOException ex) { 
       } 
      } 
     } 
    } 
} 

客戶:

import java.io.InputStream; 
import java.io.OutputStream; 
import java.net.InetAddress; 
import java.net.Socket; 
import java.util.Vector; 

public class CloseTestClient { 

    public CloseTestClient(int port, String ipAddress){ 
     Vector<Socket> connections = new Vector<Socket>(); 
     try { 
      for(int i=0;i<20;i++){ 
       Socket connection = new Socket(InetAddress.getByName(ipAddress), port); 
       connections.add(connection); 
       OutputStream out = connection.getOutputStream(); 
       out.write(("CONNECT#"+(i+1)+"#1%").getBytes()); 
       System.out.println("[CloseTestClient SENT]:"+"CONNECT#"+(i+1)+"#1%"); 
       Thread.sleep(1000); // to be sure the server threads are blocked in the read() 
       // connection.close(); // if I comment this out I see the connection reset message from the server when this main terminates 
       // commented it out finally and moved the closing at the end to be sure the server threads are blocked in read() 
      } 
     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 
     finally{ 
      // if I comment *for* out I see the "connection_reset" message from the server when this main terminates 
      for (Socket c : connections){ 
       try{ 
        c.close(); 
       }catch(Exception ex){ 
       } 
      } 
     } 
    } 

    public static void main(String args[]){ 
     System.out.println("CloseTestClient run !"); 
     new CloseTestClient(8082,"127.0.0.1"); 
    } 
} 

回答

1

你指的是文件的位適用於機器,而不是遠程線程上的線程。如果線程在socket X上有一個read(),並且同一個進程的線程B關閉套接字X,那麼線程A的讀取調用將拋出異常。

當本地計算機上的套接字關閉()時,遠程計算機可以確定沒有更多數據通過套接字傳遞,因此它返回-1(請參閱InputStream的read()文檔) 。這是在您明確關閉客戶端連接時發生的情況。服務器知道沒有更多的數據會來,所以read()愉快地返回-1。沒有特殊情況。

我猜測,如果讓客戶端在socket上調用close()而終止,則JVM或OS正在發送TCP RST,而不是很好地關閉連接(發送TCP FIN)。這會導致服務器上的read()調用引發異常。

+0

它們在同一臺計算機上 - 主機是「127.0.0.1」 - 或者您的機器是什麼意思? –

+0

對不起,本意是說在這個例子中的兩個線程是同一過程的一部分。至少我是這樣解釋文檔的。我沒有測試過它。我知道close()不會導致在套接字的另一端拋出異常。 – Neal

+0

你能指點我一些文檔嗎?你的意思是,當一個關閉()來自不同進程的套接字時,沒有異常? –

相關問題