Hướng dẫn lập trình mạng TCP Java Calculator Client Server

Mục lục

1 Đặt vấn đề

2 Ý tưởng thực hiện

3 Cách bật Telnet Client trên Windows 10

4 Sourcecode và giải thích

5 Kết quả đạt được

6 Kết luận

 

 

 

1. Đặt vấn đề

Viết Chương trình lập trình mạng Java TCP trong đó Server hỗ trợ các phép tính cơ bản (+-*/) Client tương tác với Server bằng giao thức TCP thông qua các dòng văn bản. Người dùng nhập lệnh trên Client có dạng:

1 + 2 rồi nhấp enter, Client gửi dòng dữ liệu tới Server, Server trả về kết quả có dạng:

1 + 2 = 3; xử lý các ngoại lệ các toán hạng không phải là số và phép chi cho 0.

Chương trình cho phép nhiều kết nối đồng thời và có thể sử dụng Client Telnet có sẳn trên hệ điều hành Windows để test chương trình.

2. Ý tưởng thực hiện

Để bài tập này được thực hiện một cách đầy đủ và logic ta cần thực hiện theo sơ đồ các bước sự sau:

Server

Client

Bước 1: Khởi tạo ServerSocket, SocKet

Khởi tạo BufferedReader, PrintWriter để gửi nhận các dòng văn bản với Client

Bước 1: Khởi tạo Socket, BufferedReader, PrintWriter để gửi nhận văn bản cho Server, Khởi tạo thêm BufferedReader để đọc dữ liệu từ Console

Bước 2: Gửi lời chào đến Client

Bước 2: Nhận lời chào từ Server

Bước 3: Nhận lệnh từ Client sau đó kiểm tra các toán tử toán hạng

Bước 3: Đọc lệnh từ Console cú pháp (x ? y) trong đó ? là các phép toán
Gửi lệnh qua cho Server

Bước 4:(Xử lý các toán hạng, kiểm tra các lỗi chia cho 0, toán hạng không phải là số, toán tử không phù hợp …
Gửi kết quả trả về cho Client

Bước 4: đọc kết quả trả về từ Server, in ra màn hình để kiểm tra kết quả

Phát triển bài này về dạng Server cho phép đồng thời nhiều kết nối và cho phép Client tương tác liên tục đến khi nào gặp đoạn lệnh Quit thì mới kết thúc.

3. Cách bật Telnet Client trên Windows 10:
Đầu tiên ta bấm phím Windows trên bàn phím gõ vào chữ Telnet màn hình sẽ xuất hiện cửa sổ như sau:

Sau đó ta tiếp tục chọn check vào Telnet Client như hình bên dưới

Sau khi cài xong ta gõ vào phím Window sau đó gõ lại cụm từ Telnet Client đã được hiển thị như hình dưới

4. Source code vài giải thích:

Class Server.java

package BT19_MultiConnect;

import java.net.ServerSocket;

import java.net.Socket;

public class Server {

public static void main(String[] args) {

    try {

         ServerSocket serverSocket = new ServerSocket(2222);

         System.out.println(“waiting for Client…”);

         while(true) {

             int count = 1;

             Socket socket = serverSocket.accept();

             new Server_Process(socket).start();

             count++;

             System.out.println(“Client “+socket.getInetAddress()+ ” connected!”);

         }

    } catch (Exception e) {

         e.printStackTrace();

    }

}

}

Class Server_Process.java

package BT19_MultiConnect;

import java.io.BufferedReader;

import java.io.DataOutputStream;

import java.io.InputStreamReader;

import java.io.OutputStreamWriter;

import java.io.PrintWriter;

import java.net.ServerSocket;

import java.net.Socket;

import java.util.StringTokenizer;

public class Server_Process  extends Thread{

    //DataOutputStream dos;

    PrintWriter dos;

    BufferedReader dis;

    ServerSocket serverSocket;

    Socket socket;

    public Server_Process(Socket socket) {

         try {

             this.socket =socket;

             dis = new BufferedReader(new InputStreamReader(socket.getInputStream()));

             dos = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()),true);

         } catch (Exception e) {

             e.printStackTrace();

         }

    }

    @Override

    public void run() {

         try {

             dos.println(“Hello Client!”);

             dos.flush();

             while(true) {

             String command = dis.readLine();

             if(command.equalsIgnoreCase(“Quit”)) {

                 dos.println(“Bye Client !!!”);

                 dis.close();

                 dos.close();

                 break;

             }

             else {      

//           System.out.println(command);

//           System.out.println(findOperator(command));

             String operator = findOperator(command);

             if (operator != null) {

                 double soA = 0;

                 double soB = 0;

                 double ketqua = 0;

                 StringTokenizer tokenizer = new StringTokenizer(command, operator);

                 try {

                      soA = Double.parseDouble(tokenizer.nextToken());

                      soB = Double.parseDouble(tokenizer.nextToken());

                      switch (operator) {

                      case “+”:

                          ketqua = soA + soB;

                          dos.println(soA + operator + soB+” = ” + ketqua);

                          dos.flush();

                          break;

                      case “-“:

                          ketqua = soA – soB;

                          dos.println(soA+operator + soB+” = ” + ketqua);

                          dos.flush();

                          break;

                      case “*”:

                          ketqua = soA * soB;

                          dos.println(soA+operator + soB+” = ” + ketqua);

                          dos.flush();

                          break;

                      case “/”:

                          ketqua = soA / soB;

                          dos.println(soA+operator + soB+” = ” + ketqua);

                          dos.flush();

                          break;

                      default:

                          break;

                      }

                 } catch (Exception e) {

                      dos.println(“Operand Wrong!”);

                      dos.flush();

                 }

             } else {

                 dos.println(“Input command is Wrong !”);

                 dos.flush();

             }

             }  

             }

         } catch (Exception e) {

             e.printStackTrace();

         }

    }

    public static String findOperator(String command) {

         if ((new StringTokenizer(command, “+”).countTokens() == 2)) {

             return “+”;

         }

         if ((new StringTokenizer(command, “-“).countTokens() == 2)) {

             return “-“;

         }

         if ((new StringTokenizer(command, “*”).countTokens() == 2)) {

             return “*”;

         }

         if ((new StringTokenizer(command, “/”).countTokens() == 2)) {

             return “/”;

         }

         return null;

    }

}

Class Client.java

package BT19_MultiConnect;

import java.io.BufferedReader;

import java.io.DataInputStream;

import java.io.InputStreamReader;

import java.io.PrintWriter;

import java.net.Socket;

public class Client {

BufferedReader dis;

PrintWriter dos;

Socket socket;

BufferedReader br;

public Client() {

    try {

        socket = new Socket(“localhost”, 2222);

        dis = new BufferedReader(new InputStreamReader(socket.getInputStream()));

        dos = new PrintWriter(socket.getOutputStream());

    } catch (Exception e) {

        e.printStackTrace();

    }

}

public void mainActivity() {

    try {

    String hello = dis.readLine();

    System.out.println(hello);

    while(true) {

    br = new BufferedReader(new InputStreamReader(System.in));

    String command = br.readLine();

    dos.println(command);

    dos.flush();

    String ketqua = dis.readLine();

    System.out.println(ketqua);

    if(ketqua.equalsIgnoreCase(“Bye Client !!!”)) {

        dis.close();

        dos.close();

        br.close();

        break;

    }

    }

    } catch (Exception e) {

        e.printStackTrace();

    }

}

public static void main(String[] args) {

    new Client().mainActivity();

}

}

Giải thích code:
Class Server
Ta khởi tạo ServerProcess sau đó khởi tạo đối tượng Socket bằng cách nhận Socket từ Client thông qua phương thức accept();

Sau đó ta khởi tạo Class Server_Process (đối tượng này dùng để xử lý đa tiến trình) Server cho phép đồng thời nhiều Client connect cùng lúc.

Class ServerProcess kế thừa Thread

Đây sẽ là class xử lý chính các tác vụ của Client Server thông qua đối tượng Socket.
Toàn bộ code xử lý sẽ nằm trong phương thức run();

Tại đây ServerProcess sẽ tương tác với Client thông qua đối tượng Socket gửi nhận dữ liệu văn bản thông qua cặp Stream đó là BufferedReader PrintWriter

Xử lý các phép toán, toán hạng, xử lý lỗi, thông báo kết quả cho Client.

Class Client

Lớp này chỉ có nhiệm vụ đơn giản là khởi tạo BufferedReader PrintWriter gửi nhận dữ liệu với Server đồng thời khởi tạo BufferdReader để đọc dữ liệu từ Console các phép toán.
Ta vừa có thể sử dụng Client tự viết này hoặc sử dụng Telnet Client mình đã trình bày cách bật Telnet trên windows 10 ở phần phía trên của bài viết để test.

5. Kết quả đạt được

Đầu tiên ta run Server trước

Sau đó ta khởi động Telnet Client gõ vào đoạn lệnh:
open localhost 2222

Trong đó localhost host mặc định trên máy tính của mình ta cũng có thể dùng địa chỉ IP 127.0.0.1, 2222 port open là cú pháp lệnh như hình bên dưới.
Sau khi kết nối xong ta tiếp tục thực hiện các lệnh tương ứng và kiểm tra kết quả. Lưu ý ta có thể mở 1 lúc nhiều Telnet Client và chạy thêm Client trong Console để test chương trình một lúc đồng thời nhiều kết nối.

6. Kết luận
Qua bài này mình đã hướng dẫn các bạn một bài tập rất cơ bản về giao thức TCP trong lập trình mạng Java thông qua đối tượng Socket, bài tập áp dụng này sẽ giúp các bạn hiểu rõ hơn về lập trình đa tiến trình trong Java, nhiều Client có thể kết nối đồng thời với Server thông qua đối tượng Socket. Chúc các bạn thành công !.