Xem thêm

Võ Văn Hải's blog - Sử dụng Socket với đa tiến trình trong Java

Huy Erick
Truy cập: Võ Văn Hải's blog Hình ảnh: Võ Văn Hải's blog Trong bài viết này, chúng ta sẽ cùng tìm hiểu cách sử dụng Socket trong Java với đa tiến trình. Hãy cùng xem...

Truy cập: Võ Văn Hải's blog

Hình ảnh Hình ảnh: Võ Văn Hải's blog

Trong bài viết này, chúng ta sẽ cùng tìm hiểu cách sử dụng Socket trong Java với đa tiến trình. Hãy cùng xem các bước thực hiện nhé!

Tạo lớp Server

Đầu tiên, chúng ta tạo một lớp Server bằng cách tạo một ServerSocket lắng nghe trên cổng 9999. Với chức năng đa tiến trình, chúng ta sẽ tạo một luồng (thread) mới cho mỗi kết nối từ client.

package vovanhai.wordpress.com.server;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class CalculatorServer {
    public static void main(String[] args) {
        try {
            final ServerSocket svr = new ServerSocket(9999);
            System.out.println("Server đang lắng nghe trên cổng 9999...");

            while (true) {
                Socket soc = svr.accept();
                new Thread(new CalcRunnable(soc)).start();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

class CalcRunnable implements Runnable {
    Socket client = null;

    CalcRunnable(Socket client) {
        this.client = client;
    }

    @Override
    public void run() {
        try {
            // Nhận yêu cầu từ client
            InputStream is = client.getInputStream();
            Scanner in = new Scanner(is);
            OutputStream os = client.getOutputStream();
            PrintWriter out = new PrintWriter(os, true); // auto-flush

            while (in.hasNextLine()) {
                double a = Double.parseDouble(in.nextLine());
                double b = Double.parseDouble(in.nextLine());
                char op = in.nextLine().charAt(0);

                double kq = tinhtoan(a, b, op);
                out.println(kq);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private double tinhtoan(double a, double b, char op) {
        double ret = 0;

        switch (op) {
            case '+':
                ret = a + b;
                break;
            case '-':
                ret = a - b;
                break;
            case '*':
                ret = a * b;
                break;
            case '/':
                ret = a / b;
                break;
        }

        return ret;
    }
}

Tạo lớp Client

Tiếp theo, chúng ta tạo một lớp client để thử nghiệm. Trong ví dụ này, chúng ta sẽ sử dụng giao diện đồ họa để client tương tác với Server. Dưới đây là mã nguồn của lớp client:

package vovanhai.wordpress.com.client;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;

public class CalcClientGUI extends JFrame implements ActionListener {
    private JTextField tfA, tfB, tfRes, tfAdd;
    private JButton btnCong, btnTru, btnNhan, btnChia;

    public CalcClientGUI() {
        setTitle("Mẹt Calculator");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(300, 200);
        setResizable(false);
        setLocation(100, 200);

        Box b = Box.createVerticalBox();
        Box b1 = Box.createHorizontalBox();
        Box b2 = Box.createHorizontalBox();
        Box b3 = Box.createHorizontalBox();
        Box b4 = Box.createHorizontalBox();
        Box b5 = Box.createHorizontalBox();

        JLabel l1, l2, l4;
        b5.add(l4 = new JLabel("Địa chỉ Server:", JLabel.RIGHT));
        b5.add(tfAdd = new JTextField("localhost"));

        b1.add(l1 = new JLabel("Số A:", JLabel.RIGHT));
        b1.add(tfA = new JTextField());

        b2.add(l2 = new JLabel("Số B:", JLabel.RIGHT));
        b2.add(tfB = new JTextField());

        b4.add(new JLabel("Kết quả:", JLabel.RIGHT));
        b4.add(tfRes = new JTextField());

        b3.add(btnCong = new JButton("+"));
        btnCong.addActionListener(this);
        b3.add(btnTru = new JButton("-"));
        btnTru.addActionListener(this);
        b3.add(btnNhan = new JButton("*"));
        btnNhan.addActionListener(this);
        b3.add(btnChia = new JButton("/"));
        btnChia.addActionListener(this);

        l1.setPreferredSize(l4.getPreferredSize());
        l2.setPreferredSize(l4.getPreferredSize());

        tfRes.setEditable(false);

        b.add(Box.createVerticalStrut(10));
        b.add(b5);
        b.add(Box.createVerticalStrut(10));
        b.add(b1);
        b.add(Box.createVerticalStrut(10));
        b.add(b2);
        b.add(Box.createVerticalStrut(10));
        b.add(b3);
        b.add(Box.createVerticalStrut(10));
        b.add(b4);
        b.add(Box.createVerticalStrut(10));

        this.add(b, BorderLayout.NORTH);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        Object o = e.getSource();

        try {
            double a = Double.parseDouble(tfA.getText());
            double b = Double.parseDouble(tfB.getText());
            String op = "";

            if (o.equals(btnCong)) {
                op = "+";
            } else if (o.equals(btnTru)) {
                op = "-";
            } else if (o.equals(btnNhan))
                op = "*";
            else if (o.equals(btnChia))
                op = "/";

            Socket soc = new Socket(tfAdd.getText(), 9999);
            Scanner in = new Scanner(soc.getInputStream());
            PrintWriter out = new PrintWriter(soc.getOutputStream(), true);

            out.println(a);
            out.println(b);
            out.println(op);

            String kq = in.nextLine();
            tfRes.setText(kq);
        } catch (Exception e2) {
            JOptionPane.showMessageDialog(null, e2.getMessage());
        }
    }

    public static void main(String[] args) {
        new CalcClientGUI().setVisible(true);
    }
}

Biên dịch và chạy

Sau khi đã hoàn thành việc viết mã nguồn, chúng ta tiến hành biên dịch 2 file này. Để dễ thao tác, ta có thể tạo các file .bat như sau (đảm bảo bạn đã thiết lập biến môi trường PATH):

File build.bat dùng để biên dịch:

javac -d . -encoding UTF-8 *.java
pause

Tạo file RunServer.bat với nội dung sau để chạy Server:

java vovanhai.wordpress.com.server.CalculatorServer
pause

Tạo file RunClient.bat với nội dung sau để chạy Client:

java vovanhai.wordpress.com.client.CalcClientGUI
pause

Bạn chỉ cần chạy file build.bat để biên dịch các file Java. Sau khi biên dịch, nếu không có lỗi, bạn sẽ nhận được cấu trúc thư mục như sau:

vovanhai.wordpress.com
|-- client
|   |-- CalcClientGUI.class
|   `-- CalcClientGUI.java
`-- server
    |-- CalculatorServer.class
    `-- CalculatorServer.java

Tiếp theo, chạy file RunServer.bat để khởi động Server. Bạn sẽ thấy thông báo như sau:

Server Hình ảnh: Chạy Server

Cuối cùng, chạy file RunClient.bat để mở giao diện client:

Client Hình ảnh: Chạy Client

Bạn có thể triển khai phần Server trong máy chủ của mình và chạy Client trên máy tính cá nhân. Hãy nhập đúng địa chỉ/tên máy chủ vào ô "Địa chỉ Server" và giá trị cần tính vào 2 ô textfield còn lại. Bạn sẽ nhận được kết quả sau khi nhấn nút tương ứng.

Chúc bạn thành công!

1