0

为什么IOException在数千个套接字创建调用之后?

我做了一个简单的服务器代码(Java),它接受连接然后创建一个线程读取套接字并将另一个字符发送回客户端客户端代码开始循环(足够长以重现问题)并且在每个循环中创建 50 个线程在每个线程中创建一个客户端套接字到服务器机器并发送一个字符,然后从套接字读取服务器发回的字符。然后客户端和服务器都关闭套接字。

过了一会儿,我注意到在客户端创建客户端套接字时出现异常。我应该考虑一些限制才能正常工作还是应该在无限循环中工作?

我在这里考虑的情况是,可能在足够长的循环时间之后,客户端尝试将新套接字绑定到客户端机器上的端口,该端口仍绑定到处于 CLOSED 状态但需要的时间段已过被尚未通过的内核释放。(抱歉不知道这个时间段的正式名称)客户端和服务器机器是VMware中的两个Linux系统。

4

3 回答 3

0

听起来您的连接可能已断开。

你忘记了分布式计算的谬误中的第一条规则:网络总是可靠的。

于 2013-05-15T15:44:34.747 回答
0

谢谢 !实际上这是我的服务器端代码

public class TestServer {

  public void createThread() {
    System.out.println("createThread");
    ServerThread servThread = new ServerThread();
    servThread.start();   
  }

  public static final void main(String[] args) {

    ServerSocket server = null;

    try {
      System.out.println("Started");
      server = new ServerSocket(12345);
    }
    catch(IOException ex) {
      System.out.println("Server: Exception at socket creation: " + ex.getMessage());
    }

    try {
      while(true) {
        Socket clientSock = server.accept();
        System.out.println("Connection Accepted: server: "+clientSock.getLocalPort()+", Client: "+clientSock.getPort());
        ServerThread servThread = new ServerThread(clientSock);
        servThread.start();
      }
    }
    catch(IOException ex) {
      System.out.println("Server: Exception at socket accept: " + ex.getMessage());
    }

  }
}

class ServerThread extends Thread {

  private Socket sock;

  public ServerThread() {}

  public ServerThread(Socket sock) {
    this.sock = sock;
  }

  public void run() {
    InputStream is = null;
    OutputStream os = null;
    try {
      is = sock.getInputStream();
      os = sock.getOutputStream();
    }
    catch(IOException ex) {}  

    try {     
      int b = is.read();
      System.out.println("server: received = " + (char)b);
    }
    catch(IOException ex) {
      System.out.println("Server: IOException at read = " + ex.getMessage());
    }

    try {
      os.write('R');
      os.flush();
    }
    catch(IOException ex) {
      System.out.println("Server: IOException at write = " + ex.getMessage());
    }

    try {
      sock.close();
    }
    catch(IOException ex) {
      System.out.println("Server: IOException at close = " + ex.getMessage());
    }
  }
}

这是客户端部分:

public class TestClient {

  public static void main(String[] args) {

    if (args.length != 4) {
      System.out.println("Usage: java TestClient <ServerIP> <nbThreads> <cycle> <delay>");
      System.exit(1);
    }

    String host   = args[0];
    int nbThreads = Integer.parseInt(args[1]);
    int cycle     = Integer.parseInt(args[2]);
    int delay     = Integer.parseInt(args[3]);

    for (int i = 0; i<cycle; i++) {
      for (int j = 0; j<nbThreads; j++) {
        ClientThread clThread = new ClientThread(host);
        clThread.start();
      }
/*      try {
        Thread.sleep(delay);
      }
      catch (Exception ex) {} */
    }
  }
}

class ClientThread extends Thread {

  private String host;

  public ClientThread(String host) {
    this.host = host;
  }

  public void run(){

    for (int i=0; i<3; i++) {
      Socket clientSock = null;
      try {
        clientSock = new Socket(host, 12345);
      }
      catch(IOException ex) {
        System.out.println("Client: IOException at socket creation = " + ex.getMessage());
      }

      OutputStream os = null;
      InputStream  is = null;
      try {
        os = clientSock.getOutputStream();
        is = clientSock.getInputStream();
      }
      catch (IOException ex) { }

      try {
        os.write('B');
        os.flush();
      }
      catch (IOException ex) {
        System.out.println("Client: IOException at write = " + ex.getMessage());
      }

      try {
        int reply = is.read();
        System.out.println("Client: reply = " + (char)reply);
      }
      catch(IOException ex) {
        System.out.println("Client: IOException at read = " + ex.getMessage());
      }

      try {
        clientSock.close();
      }
      catch(IOException ex) {
        System.out.println("Client: IOException at close = " + ex.getMessage());
      }
    }
  }
}

我正在使用 60 个线程和 1000 个周期进行测试,并且没有延迟。

我的第一个问题错了,异常来自 is.read() 一段时间后的调用,它是“连接重置”异常。我做了这个示例代码来模拟我在我的应用程序代码中遇到的问题,我在客户端套接字创建期间遇到了异常......但似乎我需要进一步找到这个和我的应用程序代码之间的区别. 但是我认为这也有助于我理解为什么一段时间后我会在一段时间后在客户端收到“连接重置”异常。是否有可能在服务器端一旦 os.write('R') 发生 sock.close() 发生得如此之快以至于客户端上的 is.read() 调用尚未到达。听起来很奇怪:)

也不确定我应该在哪个套接字上使用 setReuseAddress 函数。不在客户端,因为我在那里一次又一次地创建套接字......虽然现在我没有在客户端套接字创建时遇到异常。谢谢 !

于 2013-05-16T09:31:20.960 回答
0

您是否setReuseAddress在 ServerSocket 上将参数设置为 true?如果没有,您必须等待相当长的时间才能让内核释放网络资源。

于 2013-05-15T15:56:00.877 回答