如何确保TCP套接字是否在另一端关闭? (如何读取ack信号)

时间:2012-03-05 19:28:40

标签: java sockets telnet

考虑下面的java伪代码(clisent用IP和端口23(telnet)打开一个到服务器的套接字:

  static Socket skt = null;   
  skt = new Socket(IP, 23);
  do something
  skt.close()
  ALMOST NO DELAY
  skt = new Socket(IP, 23); // re-opening same socket variable (skt) right after closing it

..并且有时会发生异常,因为我们正在尝试重新打开尚未完全关闭的同一个套接字 错误:java.io.IOException:连接重置

如何确保(检查)套接字在另一端关闭?换句话说,在我们继续并在另一部分代码中重新打开该套接字之前,等待来自服务器的确认。 - 由于某种原因,我们必须重新打开相同的插座 - 我们也不想在重新打开相同的套接字之前放置延迟。

简而言之:我们希望从服务器读取确认(蓝线)

enter image description here

3 个答案:

答案 0 :(得分:2)

套接字由两端,源和目标中的IP和端口标识。您的第二个连接应该获得不同的源端口,因此服务器将其视为单独的连接。确保服务器始终接受新连接,您应该没问题。

答案 1 :(得分:1)

每次创建客户端套接字的本地端口后都打印它。如果为每个新的客户端套接字获得一个新的本地端口,除非TCP堆栈中存在错误,否则它实际上不太可能是“套接字重用”的问题。那么,您是否通过例如明确指定本地套接字号码? Socket.bindthe Socket constructor which accepts a local port?你可能不应该。让系统选择一个短暂的端口。


问题可能出在服务器上,而不是客户端。当我关闭然后立即重新创建到同一主机和端口的客户端套接字时,我没有问题。在我退出之前,SSCCE在没有任何问题的情况下达到130k连接。环回接口可能比真实的NIC更宽容,但您可以轻松修改此代码以在真实网络上运行。

public class TestTcpClientServer
{
    public static final int SERVER_PORT = 10111;

    public static void main(String[] args) throws Exception
    {
        Server server = new Server();
        server.start();

        Thread.sleep(500);

        Client client = new Client();
        client.start();

        System.out.println("Press enter to shutdown...");

        System.in.read();

        client.shutdown();
        client.join();
        server.shutdown();
        server.join();

        System.out.println("Done.");
    }

    public static class Client extends Thread
    {
        private volatile boolean shutdown = false;

        public void run()
        {
            try
            {
                int totalClientConnections = 0;

                while (!shutdown)
                {
                    Socket socket = new Socket("localhost", SERVER_PORT);

                    InputStream inputStream = socket.getInputStream();
                    BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));

                    OutputStream outputStream = socket.getOutputStream();
                    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));

                    bw.write("Client saying hello to server");
                    bw.newLine();
                    bw.flush();

                    String readLine = br.readLine();
                    //System.out.println("Client read from server: " + readLine);

                    System.out.println("Socket local port: " + socket.getLocalPort());

                    socket.close();

                    totalClientConnections++;
                    if (totalClientConnections % 10000 == 0)
                    {
                        System.out.println("totalClientConnections=" + totalClientConnections);
                    }

                    Thread.sleep(1000);
                }
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }

        public void shutdown()
        {
            shutdown = true;
        }
    }

    public static class Server extends Thread
    {
        private volatile boolean shutdown = false;
        private ServerSocket serverSocket = null;

        public void run()
        {
            try
            {
                int totalServerConnections = 0;

                serverSocket = new ServerSocket(SERVER_PORT);

                while (!shutdown)
                {
                    Socket socket = serverSocket.accept();

                    InputStream inputStream = socket.getInputStream();
                    BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));

                    OutputStream outputStream = socket.getOutputStream();
                    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));

                    String readLine = br.readLine();
                    //System.out.println("Server read from client: " + readLine);

                    bw.write("Server saying hello to client");
                    bw.newLine();
                    bw.flush();

                    socket.close();

                    totalServerConnections++;
                    if (totalServerConnections % 10000 == 0)
                    {
                        System.out.println("totalServerConnections=" + totalServerConnections);
                    }
                }
            }
            catch (Exception e)
            {
                if (!shutdown)
                {
                    e.printStackTrace();
                }
            }
        }

        public void shutdown()
        {
            shutdown = true;
            try
            {
                serverSocket.close();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }
}

答案 2 :(得分:0)

  

..并且有时会发生以下异常,因为我们正在尝试   重新打开尚未完全关闭的同一插座错误:   java.io.IOException:连接重置

您的分析不正确。那不是原因。插座是全新的。这种联系是全新的。如果您有“连接重置”,那是因为服务器软件选择重置连接。除非调查原因,最糟糕的睡眠和重试,否则你无法做到这一点。

这也与本地端口耗尽无关,正如其他一些答案所暗示的那样。如果那是问题,你会得到一个BindException

您的客户端发送RST这一事实非常好奇。您是否正在调用上面未显示的一些Socket API?