套接字连接重置仍然无法理解

时间:2014-06-16 00:19:19

标签: java multithreading sockets

问题是什么:

基于Java Socket的服务器程序似乎虚假地重置了它在已建立的连接中与基于Java套接字的客户端的连接,尽管数据传输的SO_TIMEOUT设置被设置为"无限&#34 ;

我测试了服务器:

Linux Ubuntu 14.04 LTS内核3.13.0-29-通用Java(TM)SE运行时环境(版本1.7.0_03-b04) 并且 Windows 8.1版本6.3.9600 Java(TM)SE运行时环境(版本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

1 个答案:

答案 0 :(得分:0)

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

在服务器和客户端完全摆脱这一行。除了我在评论中所说的,这是激发连接重置的另一种方法。只需删除它。你不需要它。这是一个问题,而不是解决方案。