C, PHP, VB, .NET

Дневникът на Филип Петров


* Пример за приложения използващи сокети

Публикувано на 31 октомври 2011 в раздел ПИК3 Java.

В представеното приложение е реализирана възможно най-базовата комуникация между клиент и сървър, при която се разменят поредица от текстови съобщения. Обърнете внимание, че не се използват нишки, т.е. за една "сесия" сървърът може да комуникира само с един клиент.

Server.java:

import java.io.PrintWriter;
import java.net.Socket;
import java.net.ServerSocket;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.Scanner;

public class Server{
  public static void main(String args[]) {
    ServerSocket serverSocket = null;
    Socket connection = null;
    Scanner socketIn = null;
    PrintWriter socketOut = null;
    int port = 1234;

    // Безкраен цикъл - сървъра ще приема връзки
    // докато програмата не бъде спряна принудително
    while(true){
      try {
        serverSocket = new ServerSocket(port);
        System.out.println("Сървъра очаква свързване...");
        connection = serverSocket.accept();
        System.out.println("Свърза се клиент:"
              +connection.getInetAddress().getHostName()
        );

        System.out.println("Подавам съобщение на клиента...");
        socketOut = new PrintWriter(connection.getOutputStream(), true);
        socketOut.println("Възможните команди са \"hi\" и \"exit\"");

        System.out.println("Сървъра очаква подаване на команда...");
        socketIn = new Scanner(new BufferedReader(
                          new InputStreamReader(connection.getInputStream()))
                       );

        String command = null;
        loop: do{
          socketOut.flush();
          command = socketIn.nextLine();
          switch(command){
            case "hi":
              System.out.println("Клиентът подаде команда \"hi\"");
              socketOut.println("OK");
              break;
            case "exit":
              System.out.println("Клиентът подаде команда \"exit\"");
              socketOut.println("OK");
              break loop;
            default:
              System.out.println("Получих непозната команда");
              socketOut.println("Не познавам тази команда");
              break;
          }
        }
        while(!command.equalsIgnoreCase("exit"));
        System.out.println("Затварям връзката с "
                             +connection.getInetAddress().getHostName()
                          );
      }
      catch(IOException e) {
        e.printStackTrace();
      }
      finally{
        try{
          if (socketIn!=null) socketIn.close();
          if (socketOut!=null) socketOut.close();
          if (connection!=null) connection.close();
          if (serverSocket!=null) serverSocket.close();
        }
        catch(IOException e){
          System.err.println("Не може да бъде затворен сокет");
        }
      }
    }
  }
}

 

Client.java:

import java.io.PrintWriter;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Scanner;
import java.net.Socket;
import java.io.IOException;
import java.net.ConnectException;

public class Client{
   public static void main(String args[]){
     Socket connection = null;
     Scanner socketIn = null;
     PrintWriter socketOut = null;
     Scanner keyboardIn = new Scanner(System.in);
     int port = 1234;
     String host = "localhost";

     try{
       System.out.println("Очаквам свързване със сървъра");
       try{
         connection = new Socket(host, port);
       }
       catch(ConnectException e){
         System.err.println("Не мога да осъществя връзка със сървъра");
         return;
       }
       System.out.println("Свързването със сървъра беше успешно!");

       System.out.println("Приемам първоначално съобщение от сървъра...");
       socketIn = new Scanner(new BufferedReader(
                         new InputStreamReader(connection.getInputStream()))
                      );
       System.out.println("Съобщението е: "+socketIn.nextLine());

       String command = null;
       socketOut = new PrintWriter(connection.getOutputStream(), true);
       do{
         socketOut.flush();
         System.out.print("Въведете команда: ");
         command = keyboardIn.nextLine();
         socketOut.println(command.toLowerCase());

         System.out.println("Изчакване на отговор от сървъра...");
         String answer = socketIn.nextLine();
         System.out.println("Сървърът отговори: "+answer);
       }
       while (!command.equalsIgnoreCase("exit"));
       System.out.println("Затваряне на връзката...");

     }
     catch(IOException e) {
       e.printStackTrace();
     }
     finally{
       try{
         if(socketIn!=null) socketIn.close();
         if(socketOut!=null) socketOut.close();
         if(connection!=null) connection.close();
       }
       catch(IOException e){
         System.err.println("Не може да се затвори сокета");
       }
     }
   }
}

 



15 коментара


  1. Само че не знам дали switch ще работи, тъй като Еклипс ми иска int или enum, a ние подаваме String

  2. socketIn = new Scanner(new BufferedReader(
    new InputStreamReader(connection.getInputStream()))
    );

    на този ред(от Сървър класа) ми дава грешка

  3. А на мен не.

    П.П. Ако има нужда от помощ, то е редно да се напишат поне малко подробности:

    1. Коя версия на JDK се използва?
    2. Каква е грешката?

  4. JDK 1.7, а среедата е Eclipse.
    Грешката която дава е:

    - The constructor Scanner(BufferedReader) is undefined
    - BufferedReader cannot be resolved to a type
    - InputStreamReader cannot be resolved to a type

  5. Сега се оправи като го написах наново. Явно средата не и е било до тези обекти одеве.

  6. При мен, обаче, не се получава. Макар и да казвам на Еклипс, че трябва да рънва двата файла с 1.7 (дори и на програмата с комплексните числа), не се получава. Не приема в switch да имам String

  7. Не се казва "насилствено", "принудително". Всяко нещо трябва да се назовава точно.

  8. Защо при скенера използваме InputStreamReader, за да превърнем байтовия поток в символен, а при PrintWriter не използваме OutputStreamWriter т.е. socketOut=new PrintWriter(new OutputStreamWriter(connection.getOutputStream(), true); ?

  9. Това "превръщане" в примера от статията всъщност е паразитно и ненужно, но да - забележката е уместна, би трябвало и двете да са в един стил.

    Предимството да "минава през" InputStreamWriter/OutputStreamWriter е, че по този начин може да се дефинира какъв character set се използва. В примера не е дефинирано тъй или иначе, т.е. ще се използва стандартния.

    Пример как трябва да бъдат:

    socketOut = new PrintWriter(new OutputStreamWriter(connection.getOutputStream(), "UTF-8"), true);

    socketIn = new Scanner(new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8")));

    П.П. PrintWriter даже май си има собствен буфер, вероятно затова не е слаган BufferedWriter... В документацията на сайта на Oracle ще пише дали е така.

  10. Не ставаше въпрос за BufferedReader, а защо при скенера използваме InputStreamReader за превръщане на байтовия поток в символен, а при PrintWriter НЕ използваме OutputStreamWriter за превръщане на байтовия поток в символен?

Добави коментар

Адресът на електронната поща няма да се публикува


*