2014-06-16 55 views
-3

是什麼問題:Socket連接復位仍然沒有完全理解

看起來不合邏輯一個Java Socket技術的基於服務器的程序重置它在已建立連接的中間連接到Java套接字基於客戶端,儘管數據SO_TIMEOUT的設置轉移被設定爲 「無限」

我測試的服務器:

Linux操作系統Ubuntu 14.04 LTS內核3.13.0-29,通用的Java(TM)SE運行時環境(建立1.7.0_03-B04) 和on Windows 8.1版本6.3.9600 Java™SE運行時環境(bui ld 1.7.0_51-b13)

而且有區別。在Windows中,服務器在所有線程繁忙且使用積壓時都不接受連接,所以應該如此。在Linux連接被接受的情況下,數據可以被寫入和刷新(除了TCP_NODELAY),但是在隨後由客戶端讀取時,其現在和接收「連接重置」。我在服務器端沒有任何例外。 如果客戶端在Windows或Linux下運行,在環回地址,本地網絡地址或外部網絡地址上運行服務器時沒有任何變化。

任何幫助或貢獻將是非常受歡迎的。我也在這裏學習,所以如果我犯了編碼錯誤就告訴我。

在之前的文章中,沒有添加源代碼,而沒有鏈接到我的網站上的JAR和源圖片。我同意這在這裏並不常見,所以我提出了一個濃縮版本,它也揭示了這個問題。請注意,所有設置都是故意選擇的,以使服務器處於超載狀態,超時連接和讀取設置爲「無限」。我意識到這些不是在「現實生活」中選擇的人,而只是產生「連接重置」。

這是客戶端的代碼:

package resetconntest; 

import java.io.BufferedReader; 
import java.io.InputStreamReader; 
import java.io.OutputStreamWriter; 
import java.io.PrintWriter; 
import java.net.InetSocketAddress; 
import java.net.Socket; 
import java.util.concurrent.Semaphore; 

class MiniClient { 

    static boolean SHOW_EXC_ONLY = true; // show exceptions only 
    static int  THREADS  = 64;  // number of "simultaneous connections" 
    static int  LOOPS   = 256; // total number of connections 
    static String HOST   = "192.168.0.10"; // server hostname 
    static int  PORT   = 7272;   // server port 
    static int  CONN_TIMEOUT = 0;  // keep infinite connect time for test 
    static int  SO_TIMEOUT = 0;  // keep infinite read time for test 
    static int  SO_LINGER  = -1;  // no linger 
    static boolean REUSE_ADDRESS = false; // chosen for test 
    static boolean TCP_NODELAY = true; // small blocks, so no Nagle 
    static boolean KEEP_ALIVE = false; // chosen for test 
    static int  TRAFFIC_CLASS = 0;  // if used, use mask as for ToS 

    public static void main (String[] args) { 
    new MiniClient().runTest(); 
    System.exit (0); 
    } 

    MiniClient() {} 

    void runTest() { 
    Object syncer = new Object(); 
    System.out.println ("--> start MiniClient"); 
    try { 
     Semaphore semaphore = new Semaphore (THREADS); 
     for (int x = 0 ; x < LOOPS ; x++) { 
     semaphore.acquireUninterruptibly(); 
     new Requester (syncer ,x + 1 ,semaphore).start(); 
     } 
     while (semaphore.availablePermits() < THREADS) { 
     Thread.sleep (100); 
     } 
    } catch (Throwable anyThrown) { 
     synchronized (syncer) { 
     System.out.println ("--> throwable in main"); 
     anyThrown.printStackTrace (System.out); 
     System.out.println ("<-- throwable in main"); 
     } 
    } 
    System.out.println ("<-- end MiniClient"); 
    } 

    class Requester extends Thread { 
    Object syncer; 
    String index; 
    Semaphore semaphore; 

    Requester (Object syncer ,int index ,Semaphore semaphore) { 
     this.syncer = syncer; 
     this.index  = Integer.toString (index); 
     this.semaphore = semaphore; 
    } 

    public void run() { 
     try { 
     Socket socket = new Socket(); 
     socket.connect   (new InetSocketAddress (HOST ,PORT) ,CONN_TIMEOUT); 
     socket.setSoTimeout (SO_TIMEOUT); 
     socket.setSoLinger  ((SO_LINGER >= 0) ,SO_LINGER); 
     socket.setReuseAddress (REUSE_ADDRESS); 
     socket.setTcpNoDelay (TCP_NODELAY); 
     socket.setKeepAlive (KEEP_ALIVE); 
     if (TRAFFIC_CLASS != 0) socket.setTrafficClass (TRAFFIC_CLASS); 
     PrintWriter out = new PrintWriter (new OutputStreamWriter (socket.getOutputStream())); 
     BufferedReader in = new BufferedReader (new InputStreamReader (socket.getInputStream() )); 

     if (dialog ("aaaaa" ,out ,in)) 
     if (dialog ("bbbbb" ,out ,in)) 
      dialog ("close" ,out ,in); 

     socket.shutdownInput(); 
     socket.shutdownOutput(); 
     in.close(); 
     out.close(); 
     socket.close(); 
     } catch (Throwable anyThrown) { 
     synchronized (syncer) { 
      System.out.println ("--> throwable in client thread:" + index); 
      anyThrown.printStackTrace (System.out); 
      System.out.println ("<-- throwable in client thread:" + index); 
     } 
     } 
     semaphore.release(); 
    } 

    boolean dialog (String   text 
        ,PrintWriter out 
        ,BufferedReader in) throws Throwable { 
     String msg = index + ':' + text; 
     try { 
     if (SHOW_EXC_ONLY == false) synchronized (syncer) { System.out.println ("--> send: " + msg); } 
     out.println (msg); 
     out.flush(); 
     String resp = in.readLine(); 
     if (resp == null) { 
      synchronized (syncer) { System.out.println ("<-- got EOF after: " + msg); } 
      return false; 
     } 
     if (SHOW_EXC_ONLY == false) synchronized (syncer) { System.out.println ("<-- received: " + resp); } 
     } catch (Throwable anyThrown) { 
     synchronized (syncer) { 
      System.out.println ("--> throwable in client thread:" + index); 
      System.out.println ("--> at processing message: " + msg); 
      anyThrown.printStackTrace (System.out); 
      System.out.println ("<-- at processing message: " + msg); 
      System.out.println ("<-- throwable in client thread:" + index); 
     } 
     return false; 
     } 
     return true; 
    } 
    } // end of inner class 

} // end of code 

這是該服務器的代碼:

package resetconntest; 

import java.io.BufferedReader; 
import java.io.InputStreamReader; 
import java.io.OutputStreamWriter; 
import java.io.PrintWriter; 
import java.net.InetAddress; 
import java.net.InetSocketAddress; 
import java.net.ServerSocket; 
import java.net.Socket; 
import java.util.concurrent.Semaphore; 

class MiniServer { 

    static boolean SHOW_EXC_ONLY  = false; // show messages and exceptions 
    static String HOST     = "192.168.0.10"; // host name binded to 
    static int  PORT     = 7272;   // port number binded to 
    static int  ACC_TIMEOUT   = 0;  // keep timeout for accept infinite for test 
    static boolean REUSE_SERVER_ADDRESS = false; // chosen for test 
    static int  BACKLOG    = 2;  // keep low for test 
    static int  THREADS    = 8;  // keep low for test 
    static int  SO_TIMEOUT   = 0;  // keep infinite read timeout for test 
    static int  SO_LINGER   = -1;  // no lingering 
    static boolean REUSE_ACC_ADDRESS = false; // chosen for test 
    static boolean TCP_NODELAY   = true; // small blocks, so no Nagle 
    static boolean KEEP_ALIVE   = false; // chosen for test 
    static int  TRAFFIC_CLASS  = 0;  // if used, use mask as for ToS 
    static int  PROCESS_DELAY  = 500; // simulate long message processing 0.5 sec 

    public static void main (String[] args) { 
    new MiniServer().runTest(); 
    System.exit (0); 
    } 

    MiniServer() {} 

    public void runTest() { 
    Object syncer = new Object(); 
    System.out.println ("--> start MiniServer"); 
    try { 
     InetSocketAddress socketAddress = new InetSocketAddress (InetAddress.getByName (HOST), PORT); 
     ServerSocket  serverSocket = new ServerSocket(); 
     serverSocket.bind   (socketAddress ,BACKLOG); 
     serverSocket.setReuseAddress (REUSE_SERVER_ADDRESS); 
     serverSocket.setSoTimeout (ACC_TIMEOUT); 
     Semaphore semaphore = new Semaphore (THREADS); 
     Socket accepted; 
     while (true) { 
     semaphore.acquireUninterruptibly(); 
     accepted = serverSocket.accept(); 
     new Servicer (syncer ,accepted ,semaphore).start(); 
     } 
     // never reached, gives the warning at server construction. 
     // to end the server, just use the old fashioned blunt CTRL-C 
     // while (semaphore.availablePermits() < THREADS) { 
     // Thread.sleep (100); 
     // } 
     // serverSocket.close(); 
    } catch (Throwable anyThrown) { 
     synchronized (syncer) { 
     System.out.println ("--> throwable in main"); 
     anyThrown.printStackTrace (System.out); 
     System.out.println ("<-- throwable in main"); 
     } 
    } 
    System.out.println ("<-- end MiniServer"); 
    } 

    class Servicer extends Thread { 
    Object syncer; 
    Socket socket; 
    Semaphore semaphore; 

    Servicer (Object syncer 
       ,Socket socket 
       ,Semaphore semaphore) { 
     this.syncer = syncer; 
     this.socket = socket; 
     this.semaphore = semaphore; 
    } 

    public void run() { 
     try { 
     socket.setSoTimeout (SO_TIMEOUT); 
     socket.setSoLinger  ((SO_LINGER >= 0) ,SO_LINGER); 
     socket.setReuseAddress (REUSE_ACC_ADDRESS); 
     socket.setTcpNoDelay (TCP_NODELAY); 
     socket.setKeepAlive (KEEP_ALIVE); 
     if (TRAFFIC_CLASS != 0) socket.setTrafficClass (TRAFFIC_CLASS); 
     BufferedReader in = new BufferedReader(new InputStreamReader (socket.getInputStream() )); 
     PrintWriter out = new PrintWriter (new OutputStreamWriter (socket.getOutputStream())); 
     String   clientMessage; 
     while (true) { 
      clientMessage = in.readLine(); 
      if (clientMessage == null) { 
      synchronized (syncer) { System.out.println ("<-> received end of file from accepted socket"); } 
      break; 
      } 
      if (SHOW_EXC_ONLY == false) synchronized (syncer) { System.out.println ("client said: " + clientMessage); } 
      if (PROCESS_DELAY > 0) Thread.sleep (PROCESS_DELAY); 
      out.println ("echo: " + clientMessage); 
      out.flush(); 
      if (clientMessage.indexOf ("close") >= 0) break; 
     } 
     socket.shutdownInput(); 
     socket.shutdownOutput(); 
     in.close(); 
     out.close(); 
     socket.close(); 
     } catch (Throwable anyThrown) { 
     synchronized (syncer) { 
      System.out.println ("--> throwable in server thread"); 
      anyThrown.printStackTrace (System.out); 
      System.out.println ("<-- throwable in server thread"); 
     } 
     } 
     semaphore.release(); 
    } 

    } // end of inner class 

} // end of code 
+2

除非您有具體的問題,否則您的帖子超出了本網站的範圍。 –

+0

你能解釋一下爲什麼嗎?我剛剛得到了一個Java編程問題,我用口頭描述。我看到很多人對我遇到的問題都有同樣的問題。 – user3735839

+0

[我可以在這裏問什麼主題?](http://stackoverflow.com/help/on-topic); [我如何問一個好問題?](http://stackoverflow.com/help/how-to-ask) –

回答

0
socket.setSoLinger((SO_LINGER >= 0) ,SO_LINGER); 

完全擺脫這一行的,在服務器和客戶端。除了我在評論中所說的,這是引發連接重置的另一種方式。只要刪除它。你不需要它。這是一個問題,而不是解決方案。

+0

感謝您的評論,我立即嘗試。但是,唉,除了我可能少了幾次「連接重置」,連接到服務器的一些「連接超時」之外,沒有什麼變化,因爲它應該是。我通過最大化線程數量,使用信號量和模擬長處理時間來延遲ServerSocket上的連續accept()調用,我意識到這一點,我會這麼做以減輕服務器負擔。難道我違反了一些我不知道的時間計劃? – user3735839

+0

我「Wiresharked」的對話框,確實服務器端確實發送RST但是爲什麼? – user3735839

+0

我不知道是否有人給我的測試程序嘗試..... – user3735839