Lập trình mạng

Khái niệm lập trình mạng (network programming) nói về viết các chương trình mà thực thi qua nhiều thiết bị, trong đó các thiết bị này được kết nối mạng với nhau.

Gói java.net của J2SE API chứa một tập hợp các class và interface mà cung cấp chi tiết về giao tiếp tầm thấp, cho phép bạn viết các chương trình mà trọng tâm vào giải quyết vấn đề trong tầm tay.

Gói java.net cung cấp sự hỗ trợ cho hai giao thức mạng phổ biến:

  • TCP: Transmission Control Protocol cho phép sự giao tiếp đáng tin cậy giữa hai ứng dụng. TCP đặc trưng được sử dụng qua Internet Protocol, được xem như là TCP/IP.
  • UDP: User Datagram Protocol là một giao thức phi kết nối, cho phép các gói nhỏ dữ liệu được truyền tải giữa các ứng dụng mà không cần khởi tạo kết nối.

Lập trình Socket trong Java

Các Socket cung cấp kỹ thuật giao tiếp giữa hai máy tính sử dụng TCP. Một chương trình Client tạo một socket trên đầu cuối của giao tiếp và cố gắng để kết nối socket đó tới một Server.

Khi kết nối được tạo, Server tạo một đối tượng Socket trên đầu cuối của giao tiếp. Client và Server bây giờ có thể giao tiếp bằng việc đọc và ghi từ Socket.

Lớp java.net.Socket biểu diễn một Socket, và lớp java.net.ServerSocket cung cấp một kỹ thuật cho chương trình Server để nghe thông tin từ các Client và thành lập các kết nối với chúng.

  1. Server khởi tạo một đối tượng ServerSocket, biểu thị số hiệu cổng (port) nào để xuất hiện giao tiếp.
  2. Server gọi phương thức accept() của lớp ServerSocket. Phương thức này đợi tới khi một Client kết nối với Server trên cổng đã cho.
  3. Sau khi Server đang đợi, một Client khởi tạo một đối tượng Socket, xác định tên Server và số hiệu cổng để kết nối tới.
  4. Constructor của lớp Socket cố gắng để kết nối Client tới Server và số hiệu cổng đã xác định. Nếu giao tiếp được thành lập, bây giờ Client có một đối tượng Socket có khả năng giao tiếp với Server.
  5. Trên Server-side, phương thức accept() trả về một tham chiếu tới một socket mới trên Server mà được kết nối với socket của Client.

Sau khi các kết nối được thành lập, giao tiếp có thể xảy ra bởi sử dụng I/O stream. Mỗi Socket có cả một OutputStream và InputStream. OutputStream của Client được kết nối với InputStream của Server, và InputStream của Client được kết nối với OutputStream của Server.

Các phương thức lớp ServerSocket trong Java

Lớp java.net.ServerSocket trong Java được sử dụng bởi các ứng dụng Server để thu nhận một cổng và nghe các yêu cầu từ Client.

Lớp ServerSocket có 4 constructor sau:

  • public ServerSocket(int port) throws IOException: Tạo một ServerSocket lắng nghe các yêu cầu kết nối từ khách hàng tới cổng đã chỉ định.
  • public ServerSocket(int port, int backlog) throws IOException: Đối số backlog xác định số lượng client tối đa yêu cầu kết nối chờ xử lý.
  • public ServerSocket(int port, int backlog, InetAddress address) throws IOException: Tạo một ServerSocket và liên kết nó với cổng và địa chỉ IP đã chỉ định.
  • public ServerSocket() throws IOException: Tạo một Server Socket không giới hạn. Sử dụng phương thức bind() để kết nối với Server Socket sau

Nếu ServerSocket constructor không ném một exception, nghĩa là ứng dụng của bạn đã thành công kết nối tới cổng đã xác định và sẵn sàng cho các yêu cầu của Client.

Một số phương thức phổ biến của lớp ServerSocket trong Java:

  • public int getLocalPort(): Trả về số cổng mà ServerSocket hiện đang sử dụng.
  • public Socket accept() throws IOException: Vào chế độ chờ, dừng lại tất cả mọi thứ sau đó, cho đến khi có một yêu cầu kết nối được gửi đến. Sau khi một Client kết nối, ServerSocket tạo một đối tượng và trả về một tham chiếu. Bây giờ, một kết nối TCP tồn tại giữa Client và Server, và giao tiếp có thể bắt đầu.
  • public void setSoTimeout(int timeout): Thiết lập thời gian chờ cho các hoạt động đọc/ghi trên ServerSocket đợi Client trong bao lâu.
  • public void bind(SocketAddress host, int backlog): Liên kết ServerSocket với một địa chỉ IP và cổng cụ thể. Đối số backlog xác định số lượng tối đa của các yêu cầu kết nối chờ xử lý. Sử dụng phương thức này nếu bạn đã khởi tạo đối tượng ServerSocket với constructor không có tham số

Các phương thức lớp Socket trong Java

Lớp java.net.Socket biểu diễn socket mà cả Client và Server sử dụng để kết nối với nhau. Client thu nhận một đối tượng Socket bằng việc khởi tạo nó, trong khi Server thu nhận một đối tượng Socket từ giá trị trả về của phương thức accept().

Lớp Socket có 5 constructor mà một Client sử dụng để kết nối tới một Server:

  • public Socket(String host, int port) throws UnknownHostException, IOException: Tạo một đối tượng Socket và kết nối nó đến máy chủ bằng tên miền và cổng đã chỉ định.
  • public Socket(InetAddress host, int port) throws IOException: Tạo một đối tượng Socket và kết nối nó đến máy chủ bằng địa chỉ IP và cổng đã chỉ định.
  • public Socket(String host, int port, InetAddress localAddress, int localPort) throws IOException: Tạo một đối tượng Socket và kết nối nó đến máy chủ bằng tên miền và cổng đã chỉ định. Liên kết với một địa chỉ IP và cổng cụ thể trên máy cục bộ.
  • public Socket(InetAddress host, int port, InetAddress localAddress, int localPort) throws IOException: Tạo một đối tượng Socket và kết nối nó đến máy chủ bằng địa chỉ IP và cổng đã chỉ định. Liên kết với một địa chỉ IP và cổng cụ thể trên máy cục bộ.
  • public Socket(): Tạo một Socket rời rạc. Sử dụng phương thức connect() để kết nối Socket này tới một Server

Khi Socket constructor trả về giá trị, nó không đơn giản chỉ khởi tạo một đối tượng Socket mà nó còn thực sự cố gắng kết nối tới Server và cổng đã xác định.

Một số phương thức của lớp Socket đáng quan tâm được liệt kê dưới đây. Chú ý rằng, cả Server và Client đều có một đối tượng Socket, vì thế những phương thức này có thể được gọi bởi cả Client và Server.

  • public void connect(SocketAddress host, int timeout) throws IOException: Kết nối Socket tới host đã xác định. Phương thức này chỉ cần thiết khi bạn đã khởi tạo Socket bởi sử dụng constructor không có tham số.
  • public InetAddress getInetAddress(): Trả về địa chỉ IP của máy chủ mà Socket kết nối tới.
  • public int getPort(): Trả về cổng của máy chủ mà Socket đã kết nối tới.
  • public int getLocalPort(): Trả về số cổng của Socket hiện đang sử dụng.
  • public SocketAddress getRemoteSocketAddress(): Trả về địa chỉ của máy chủ mà Socket kết nối tới.
  • public InputStream getInputStream() throws IOException: Trả về một luồng đầu vào để nhận dữ liệu từ Socket.
  • public OutputStream getOutputStream() throws IOException: Trả về một luồng đầu ra để gửi dữ liệu qua Socket.
  • public void close() throws IOException: Đóng kết nối Socket. Tất cả các luồng và tài nguyên liên quan đến Socket sẽ được giải phóng.

Các phương thức lớp InetAddress trong Java

Lớp java.net.InetAddress biểu diễn một địa chỉ Internet Protocol (IP). Dưới đây liệt kê một số phương thức hữu ích mà bạn sẽ cần trong khi lập trình Socket.

  • static InetAddress getByAddress(byte[] addr): Trả về một đối tượng InetAddress đã cung cấp địa chỉ IP thô.
  • static InetAddress getByAddress(String host, byte[] addr): Tạo một InetAddress dựa trên tên host và địa chỉ IP đã cung cấp
  • static InetAddress getByName(String host): Trả về một đối tượng InetAddress dựa trên tên miền hoặc địa chỉ IP.
  • String getHostAddress(): Trả về địa chỉ IP.
  • String getHostName(): Trả về tên miền hoặc tên máy chủ.
  • static InetAddress getLocalHost(): Trả về địa chỉ host nội bộ của đối tượng InetAddress.
  • String toString(): Biến đổi địa chỉ IP này thành một String.

Ví dụ về Socket Client trong Java

GreetingClient sau là một chương trình Client kết nối tới một Server bởi sử dụng một Socket và gửi một lời chào, và sau đó đợi một phản hồi.

import java.io.*;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

public class SocketGreetingClient {

    public static void main(String[] args) {
        try {
            String serverName = args[0];
            int port = Integer.parseInt(args[1]);
            // open a connection
            System.out.println("[Host] Connectiong to " + serverName + " on port " + port);
            Socket client = new Socket(serverName, port);
            System.out.println("[Host] Just connected to "+ client.getRemoteSocketAddress());
            // send message
            OutputStream outToServer = client.getOutputStream();
            DataOutputStream out = new DataOutputStream(outToServer);
            out.writeUTF("[Client] Hello from " + client.getLocalSocketAddress());
            // get message
            InputStream inFromServer = client.getInputStream();
            DataInputStream in = new DataInputStream(inFromServer);
            System.out.println(in.readUTF());
            // close connection
            client.close();
        } catch (IOException ex) {
            Logger.getLogger(SocketGreetingClient.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

Ví dụ về Socket Server trong Java

Chương trình GreetingServer sau là ví dụ về một ứng dụng Server sử dụng lớp Socket để lắng nghe các Client trên một số hiệu cổng đã xác định bởi một tham số dòng lệnh.

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class SocketGreetingServer extends Thread {

    private final ServerSocket serverSocket;

    public SocketGreetingServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);
        serverSocket.setSoTimeout(10000); // max 10s to close connection
    }

    @Override
    public void run() {
        while (true) {
            try {
                // starting server
                System.out.println("[Host] Waiting for client on port " + serverSocket.getLocalPort() + "...");
                Socket server = serverSocket.accept(); // block to wait request
                System.out.println("[Host] Just connected to " + server.getRemoteSocketAddress());
                // get message
                InputStream inFromClient = server.getInputStream();
                DataInputStream in = new DataInputStream(inFromClient);
                System.out.println(in.readUTF());
                // send message
                OutputStream outToClient = server.getOutputStream();
                DataOutputStream out = new DataOutputStream(outToClient);
                out.writeUTF("[Server] Thank you for connecting to " + server.getLocalSocketAddress());
                // server close
                server.close();
            } catch (SocketTimeoutException ste) {
                System.out.println("[Host] Socket timed out!");
                break;
            } catch (IOException ex) {
                System.out.println("[Host] Connection error!");
                Logger.getLogger(SocketGreetingClient.class.getName()).log(Level.SEVERE, null, ex);
                break;
            }
        }
    }

    public static void main(String[] args) {
        int port = Integer.parseInt(args[0]);
        try {
            Thread t = new SocketGreetingServer(port);
            t.start();
        } catch (IOException ex) {
            Logger.getLogger(SocketGreetingClient.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

Kết quả

Biên dịch Client và Server như sau:

# server
java SocketGreetingServer 12345
# client
java SocketGreetingClient localhost 12345

Server:

Client:

Leave a Reply

This site uses cookies to offer you a better browsing experience. By browsing this website, you agree to our use of cookies.