wtorek, 21 czerwca 2011

Socket - Połączenie klient-serwer

Dzisiaj zajmiemy się połączeniem pomiędzy klientem i serwerem przy użyciu klasy Socket. Klasa Socket pozwala na połączenie sieciowe na podanym porcie pomiędzy dwoma maszynami.

Socket (Java Platform SE 6)

Krótko o działaniu aplikacji. Po uruchomieniu serwer oczekuje na połączenie. Po połączeniu serwer wysyła do klienta komunikat "Ping" i oczekuje na odpowiedź. Jeśli klient odpowie "Pong" to serwer po 5 sekundach ponownie wysyła "Ping". W przypadku otrzymania złej odpowiedzi serwer się wyłącza.

Klient sprawdza nadchodzące komunikaty, jeśli otrzyma "Ping" to odpowiada "Pong". Dla celów testowych klient po 30 sekundach działania wyśle komunikat "Pon g" zamiast "Pong" i się wyłączy.

Linijki potrzebne do działania po stronie serwera:
/*Utworzenie na podanym porcie socketa serwera.*/
ServerSocket serverSocket = new ServerSocket(PORT);

/*Oczekiwanie na połączenie i zaakceptowanie*/
Socket clientSocket = serverSocket.accept();

/*Utworzenie strumieni wejściowego i wyjściowego*/
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(),true);
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

/*Wysłanie komunikatu*/
out.println(KOMUNIKAT);

/*Oczekiwanie i odebranie komunikatu*/
String input = in.readLine();

/*Zamknięcie strumieniu i socketów*/
out.close();
in.close();
clientSocket.close();
serverSocket.close();

Linijki potrzebne do działania po stronie klienta:
/*Połączenie z serwerem*/
Socket socket = new Socket(HOST, PORT);

/*Reszta analogicznie jak w serwerze*/


Kod źródłowy:
/* Server.java */
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class Server
{
    private static final int PORT = 50000;
    static boolean flaga = true;
    
    private static ServerSocket serverSocket;
    private static Socket clientSocket;
    
    public static void main(String[] args) throws IOException
    {
        serverSocket = null;
        try
        {
            serverSocket = new ServerSocket(PORT);
        }
        catch(IOException e)
        {
            System.err.println("Could not listen on port: "+PORT);
            System.exit(1);
        }
        
        System.out.print("Wating for connection...");
        
        Thread t = new Thread(new Runnable()
        {
            public void run()
            {
                try
                {
                    while(flaga)
                    {
                        System.out.print(".");
                        Thread.sleep(1000);
                    }
                }
                catch(InterruptedException ie)
                {
                    //
                }
                
                System.out.println("\nClient connected on port "+PORT);
            }
        });
        t.start();
        
        clientSocket = null;
        try
        {
            clientSocket = serverSocket.accept();
            flaga = false;
        }
        catch(IOException e)
        {
            System.err.println("Accept failed.");
            t.interrupt();
            System.exit(1);
        }
        
        final PrintWriter out = new PrintWriter(clientSocket.getOutputStream(),true);
        final BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        
        t = new Thread(new Runnable()
        {
            public void run()
            {
                try
                {
                    Thread.sleep(5000);
                    
                    while(true)
                    {
                        out.println("Ping");
                        System.out.println(System.currentTimeMillis()+" Ping sent");
                        
                        String input = in.readLine();
                        
                        if(input.equals("Pong"))
                        {
                            System.out.println(System.currentTimeMillis()+" Pong received");
                        }
                        else
                        {
                            System.out.println(System.currentTimeMillis()+" Wrong answer");
                            
                            out.close();
                            in.close();
                            clientSocket.close();
                            serverSocket.close();
                            break;
                        }
                        
                        
                        Thread.sleep(5000);
                    }
                }
                catch(Exception e)
                {
                    System.err.println(System.currentTimeMillis()+" Unexpected Error");
                }
            }
        });
        t.start();
    }
}

/* Client.java */
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class Client
{
    private static final int PORT = 50000;
    private static final String HOST = "localhost";
    
    public static void main(String[] args) throws IOException
    {
        Socket socket = null;
        
        try
        {
            socket = new Socket(HOST, PORT);
        }
        catch(Exception e)
        {
            System.err.println("Could not connect to "+HOST+":"+PORT);
            System.exit(1);
        }
        
        final PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
        final BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        
        Thread t = new Thread(new Runnable()
        {
            public void run()
            {
                long start = System.currentTimeMillis();
                
                while (true)
                {
                    try
                    {
                        String input = in.readLine();

                        if (input != null)
                        {
                            System.out.println(System.currentTimeMillis() + " Server: " + input);
                        }

                        if (input.equals("Ping"))
                        {
                            if(System.currentTimeMillis()-start>30000)
                            {
                                out.println("Pon g");
                                System.out.println(System.currentTimeMillis() + " Client: Pon g");
                                break;
                            }
                            
                            out.println("Pong");
                            System.out.println(System.currentTimeMillis() + " Client: Pong");
                        }
                    }
                    catch (IOException ioe)
                    {
                        //
                    }
                }
            }
        });
        t.start();
        
        out.close();
        in.close();
        socket.close();
    }
}

Output serwera:
Wating for connection..........
Client connected on port 50000
1308645130778 Ping sent
1308645130779 Pong received
1308645135779 Ping sent
1308645135779 Pong received
1308645140780 Ping sent
1308645140780 Pong received
1308645145780 Ping sent
1308645145780 Pong received
1308645150780 Ping sent
1308645150780 Pong received
1308645155781 Ping sent
1308645155781 Wrong answer

Output klienta:
1308645130778 Server: Ping
1308645130779 Client: Pong
1308645135779 Server: Ping
1308645135779 Client: Pong
1308645140780 Server: Ping
1308645140780 Client: Pong
1308645145780 Server: Ping
1308645145780 Client: Pong
1308645150780 Server: Ping
1308645150780 Client: Pong
1308645155781 Server: Ping
1308645155781 Client: Pon g

9 komentarzy:

  1. Przydatny wpis.

    OdpowiedzUsuń
  2. W jaki sposób wznowić nasłuchiwanie w porcie 50000 po przechwyceniu błędu?

    OdpowiedzUsuń
    Odpowiedzi
    1. Eliasz wystarczy usunac 92-97 linijki w klasie serwera

      Usuń
  3. Ten komentarz został usunięty przez autora.

    OdpowiedzUsuń
  4. Witam. Efektem działania mojego programu po wklejeniu powyższego kodu to napis "Wating for connection................................................................" w konsoli i wypisywanie kropek bez końca. Co może być prawdopodobną przyczyną nienawiązania połączenia? Dodam, że na czas połączenia wyłączałem firewalla i nic...

    OdpowiedzUsuń
  5. Konsola Clienta oczekuje na dane (można pisać), a server pokazuje takie coś :

    Wating for connection.........
    Client connected on port 50000
    1409056506826 Ping sent
    1409056506826 Unexpected Error

    OdpowiedzUsuń
    Odpowiedzi
    1. Właściwie to klient zamyka połączenie
      out.close();
      in.close();
      socket.close();
      i nic się nie wysyła, przed zamknięciem powinniśmy poczekać na watek aż skończy np t.join();

      Usuń
  6. Witam! w jakim programie to otworzyć?

    OdpowiedzUsuń
  7. Bardzo interesujące. Pozdrawiam serdecznie.

    OdpowiedzUsuń