Java, сервер-клиент TCP связь заканчивается RST - PullRequest
2 голосов
/ 06 апреля 2010

Я пытаюсь выяснить, нормально ли это.Потому что без ошибок соединение должно быть разорвано:

FIN ->
<- ACK
<- FIN
ACK ->

Я получаю это в конце TCP-соединения (через SSL, но я также получаю его с незашифрованным):

         From     To
1494    server  client  TCP search-agent > 59185 [PSH, ACK] Seq=25974 Ack=49460 Win=63784 Len=50
1495    client  server  TCP 59185 > search-agent [ACK] Seq=49460 Ack=26024 Win=63565 Len=0
1496    client  server  TCP 59185 > search-agent [PSH, ACK] Seq=49460 Ack=26024 Win=63565 Len=23
1497    client  server  TCP 59185 > search-agent [FIN, ACK] Seq=49483 Ack=26024 Win=63565 Len=0
1498    server  client  TCP search-agent > 59185 [PSH, ACK] Seq=26024 Ack=49484 Win=63784 Len=23
1499    client  server  TCP 59185 > search-agent [RST, ACK] Seq=49484 Ack=26047 Win=0 Len=0

Клиент нормально выходит и достигает socket.close , не следует ли затем нормально завершить соединение без сброса?

Я не могу найти ничего о TCPпотоки Java на Google ...

Вот мой код:

Сервер:

package Security;

import java.io.*;
import java.net.*;

import javax.net.ServerSocketFactory;
import javax.net.ssl.*;
import java.util.*;

public class SSLDemoServer
{
    private static ServerSocket serverSocket;
    private static final int PORT = 1234;

    public static void main(String[] args) throws IOException
    {
        int received = 0;
        String returned; 
        ObjectInputStream input = null;
        PrintWriter output = null;
        Socket client;

        System.setProperty("javax.net.ssl.keyStore", "key.keystore");
        System.setProperty("javax.net.ssl.keyStorePassword", "vwpolo");
        System.setProperty("javax.net.ssl.trustStore", "key.keystore");
        System.setProperty("javax.net.ssl.trustStorePassword", "vwpolo");

        try
        {
            System.out.println("Trying to set up server ...");
            ServerSocketFactory factory = SSLServerSocketFactory.getDefault();
            serverSocket = factory.createServerSocket(PORT);

            System.out.println("Server started!\n");
        }
        catch (IOException ioEx)
        {
            System.out.println("Unable to set up port!");
            ioEx.printStackTrace();
            System.exit(1);
        }

        while(true)
        {
            client = serverSocket.accept();
            System.out.println("Client trying to connect...");

            try
            {
                System.out.println("Trying to create inputstream...");
                input = new ObjectInputStream(client.getInputStream());
                System.out.println("Trying to create outputstream...");
                output = new PrintWriter(client.getOutputStream(), true);
                System.out.println("Client successfully connected!");

                while( true )
                {
                    received = input.readInt();
                    returned = Integer.toHexString(received);
                    System.out.print(" " + received);
                    output.println(returned.toUpperCase());
                }
            }
            catch(SSLException sslEx)
            {
                System.out.println("Connection failed! (non-SSL connection?)\n");
                client.close();
                continue;
            }
            catch(EOFException eofEx)
            {
                System.out.println("\nEnd of client data.\n");
            }
            catch(IOException ioEx)
            {
                System.out.println("I/O problem! (correct inputstream?)");
            }

            try {
                input.close();
                output.close();
            }
            catch (Exception e) {
            }
            client.close();
            System.out.println("Client closed.\n");
        }
    }
}

Клиент:

package Security;

import java.io.*;
import java.net.*;
import javax.net.ssl.*;

import java.util.*;

public class SSLDemoClient
{
    private static InetAddress host;
    private static final int PORT = 1234;

    public static void main(String[] args)
    {
        System.setProperty("javax.net.ssl.keyStore", "key.keystore");
        System.setProperty("javax.net.ssl.keyStorePassword", "vwpolo");
        System.setProperty("javax.net.ssl.trustStore", "key.keystore");
        System.setProperty("javax.net.ssl.trustStorePassword", "vwpolo");

        System.out.println("\nCreating SSL socket ...");
        SSLSocket socket = null;
        try
        {
            host = InetAddress.getByName("192.168.56.101");
            SSLSocketFactory factory = (SSLSocketFactory)
            SSLSocketFactory.getDefault();
            socket = (SSLSocket) factory.createSocket(host, PORT);
            socket.startHandshake();
        }
        catch(UnknownHostException uhEx)
        {
            System.out.println("\nHost ID not found!\n");
            System.exit(1);
        }
        catch(SSLException sslEx)
        {
            System.out.println("\nHandshaking unsuccessful ...");
            System.exit(1);
        } 
        catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("\nHandshaking succeeded ...\n");

        SSLClientThread client = new SSLClientThread(socket);
        SSLReceiverThread receiver = new SSLReceiverThread(socket);

        client.start();
        receiver.start();

        try
        {
            client.join();
            receiver.join();
            System.out.println("Trying to close...");
            socket.close();
        }
        catch(InterruptedException iEx)
        {
            iEx.printStackTrace();
        } 
        catch(IOException ioEx)
        {
            ioEx.printStackTrace();
        }

        System.out.println("\nClient finished.");
    }
}


class SSLClientThread extends Thread
{
    private SSLSocket socket;

    public SSLClientThread(SSLSocket s)
    {
        socket = s;
    }

    public void run() 
    {
        try
        {
            ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());

            for( int i = 1; i < 1025; i++)
            {
                output.writeInt(i);
                sleep(10);
                output.flush();
            } 

            output.flush();
            sleep(1000);
            output.close();
        }
        catch(IOException ioEx)
        {
            System.out.println("Socket closed or unable to open socket.");
        }
        catch(InterruptedException iEx)
        {
            iEx.printStackTrace();
        }
    }
}


class SSLReceiverThread extends Thread
{
    private SSLSocket socket;

    public SSLReceiverThread(SSLSocket s)
    {
        socket = s;
    }

    public void run()
    {
        String response = null;
        BufferedReader input = null;

        try
        {
            input = new BufferedReader(
                    new InputStreamReader(socket.getInputStream()));

            try
            {
                response = input.readLine();
                while(!response.equals(null)) 
                {
                    System.out.print(response + " ");
                    response = input.readLine();
                } 
            }
            catch(Exception e)
            {
                System.out.println("\nEnd of server data.\n");
            }    

            input.close();

        }
        catch(IOException ioEx)
        {
            ioEx.printStackTrace();
        }
    }
}

Большое спасибо, при не-SSL соединении, теперь я получаю хорошее упорядоченное завершение соединения без сброса.

НО, очевидно, этот метод не поддерживается SSLSocket?Когда я пробую это в своем клиенте SSL, я получаю следующее исключение:

Exception in thread "Thread-0" java.lang.UnsupportedOperationException: The method shutdownOutput() is not supported in SSLSocket
    at com.sun.net.ssl.internal.ssl.BaseSSLSocketImpl.shutdownOutput(Unknown Source)
    at Security.SSLClientThread.run(SSLDemoClient.java:99)

Мой новый код выглядит так:

package Security;

import java.io.*;
import java.net.*;

import javax.net.SocketFactory;
import javax.net.ssl.*;

public class SSLDemoClient
{
    private static InetAddress host;
    private static Socket socket;
    private static final int PORT = 1234;

    public static void main(String[] args)
    {
        System.setProperty("javax.net.ssl.keyStore", "key.keystore");
        System.setProperty("javax.net.ssl.keyStorePassword", "vwpolo");
        System.setProperty("javax.net.ssl.trustStore", "key.keystore");
        System.setProperty("javax.net.ssl.trustStorePassword", "vwpolo");

        System.out.println("\nCreating SSL socket ...");

        try
        {
            host = InetAddress.getByName("192.168.56.101");
            SocketFactory socketFactory = SSLSocketFactory.getDefault();
            socket = socketFactory.createSocket(host, PORT);
        }
        catch(UnknownHostException uhEx)
        {
            System.out.println("\nHost ID not found!\n");
            System.exit(1);
        }
        catch(SSLException sslEx)
        {
            System.out.println("\nHandshaking unsuccessful ...");
            System.exit(1);
        } 
        catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("\nHandshaking succeeded ...\n");

        SSLClientThread client = new SSLClientThread(socket);
        SSLReceiverThread receiver = new SSLReceiverThread(socket);

        client.start();
        receiver.start();

        try
        {
            client.join();
            receiver.join();
            System.out.println("Trying to close...");

            socket.close();
        }
        catch(InterruptedException iEx)
        {
            iEx.printStackTrace();
        } 
        catch(IOException ioEx)
        {
            ioEx.printStackTrace();
        }

        System.out.println("\nClient finished.");
    }
}


class SSLClientThread extends Thread
{
    private Socket socket;

    public SSLClientThread(Socket s)
    {
        socket = s;
    }

    public void run() 
    {
        try
        {
            ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());

            for( int i = 1; i < 1025; i++)
            {
                output.writeInt(i);
                sleep(10);
                output.flush();
            } 

            output.flush();
            sleep(1000);
            socket.shutdownOutput();
        }
        catch(IOException ioEx)
        {
            System.out.println("Socket closed or unable to open socket.");
        }
        catch(InterruptedException iEx)
        {
            iEx.printStackTrace();
        }
    }
}


class SSLReceiverThread extends Thread
{
    private Socket socket;

    public SSLReceiverThread(Socket s)
    {
        socket = s;
    }

    public void run()
    {
        String response = null;
        BufferedReader input = null;

        try
        {
            input = new BufferedReader(
                    new InputStreamReader(socket.getInputStream()));

            try
            {
                response = input.readLine();
                while(!response.equals(null)) 
                {
                    System.out.print(response + " ");
                    response = input.readLine();
                } 
            }
            catch(Exception e)
            {
                System.out.println("\nEnd of server data.\n");
            }    

            socket.shutdownInput();

        }
        catch(IOException ioEx)
        {
            ioEx.printStackTrace();
        }
    }
}

Правильно ли я его не использую?Или мой SSLSocket не правильный?Потому что с подключением без SSL проблем нет.

Ответы [ 3 ]

8 голосов
/ 06 апреля 2010

Журнал пакетов показывает, что клиент отправляет свой последний бит данных и уведомляет сервер о закрытии соединения.

Затем сервер отправляет обратно это последний бит данных (предположительно, последнее преобразованное целое число). Клиент отвечает RST, что указывает на то, что клиентский сокет был закрыт как для чтения , так и записи. больше не слушаю ".

Я не гуру Java, но похоже, что вызов .close() метода сокета OutputStream приводит к тому, что метод .close() вызывается на самом сокете. На самом деле вы хотите, чтобы это произошло здесь (после того, как клиент записал свое последнее целое число), что метод shutdownOutput() вызывается в сокете.

4 голосов
/ 06 апреля 2010

Как указывает caf, ваша проблема в том, что вы звоните close, когда вам следует звонить shutdownOutput. Это потому, что вы пытаетесь реализовать то, что называется половинным закрытием, при котором каждая сторона соединения закрывает свой выходной поток, чтобы указать одноранговому узлу, что больше нет ожидающих данных (EOF).

Объяснение разницы между закрытием и отключением см. В этом коротком SO-ответе " закрытие против выключения " и в этой более длинной статье " Отключение сокета и закрытие сокета ". Также см. Упорядоченная версия вместо сбойного соединения в Java .

0 голосов
/ 07 апреля 2010

Проблема real в том, что один конец пишет после того, как другой конец уже закрыл свой конец соединения. Это ошибка протокола приложения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...