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 và 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 và 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 và 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 là 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 là port và 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 !.