Lập trình phân tán – Lập trình Socket trong Java

1. Tổng quan

Lập trình Socket là cách viết chương trình thực trên nhiều thiết bị máy tính được kết nối với nhau sử dụng mạng.

Hai kiểu giao thức giao tiếp  có thể sử dụng lập trình cho socket: giao thức UDP (User Datagram Protocol) và giao thức TCP (Tranfer Control Protocol).

Sự khác nhau căn bản giữa hai kiểu giao thức đó là UDP  là không kết nối, có nghĩa là không có phiên (session) giữa client và server, trong khi TCP lại theo hướng kết nối, nghĩa là một kết nối riêng phải được thiết lập giữa client và server trước khi giao dịch được diễn ra.

Bài hướng dẫn này sẽ hướng dẫn lập trình Socket qua mạng TCP/IP và hướng dẫn cách viết ứng dụng client/server trong Java.

2. Cài đặt Project



Java cung cấp một tập các class và các interface để thực hiện giao tiếp cấp thấp giữa client và server.

Hầu hết nó nằm trong gói java.net, vì vậy chúng ta có thể import theo câu lệnh:


import java.net.*;

Chúng ta cũng cần gói java.io để chúng ta thực hiện vào ra (input/output)  để đọc và ghi khi giao tiếp:


import java.io.*;

Vì mục đích đơn giản, chúng ta sẽ chạy các chương trình client và server trên cùng một máy tính. Nếu chúng ta muốn thực thi chúng trên các máy tính nối mạng khác, thì chỉ cần thay đổi là địa chỉ IP, trong trường hợp này, chúng ví dụ này chúng ta sẽ sử dụng localhost với địa chỉ IP: 127.0.0.1.

3. Lập trình Socket sử dụng giao thức TCP

Viết một ứng dụng đơn giản client/server, thực hiênj giao tiếp giữa client và server, client gửi lời chào tới server và server sẽ phản hồi lại.

3.1. Ví dụ code phía server


import java.net.*;
import java.io.*;
public class GreetServer {
    private ServerSocket serverSocket;
    private Socket clientSocket;
    private PrintWriter out;
    private BufferedReader in;

    public void start(int port) throws IOException {
        serverSocket = new ServerSocket(port);
        clientSocket = serverSocket.accept();
        out = new PrintWriter(clientSocket.getOutputStream(), true);
        in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        String greeting = in.readLine();
        System.out.println("Server đã nhận được message:"+greeting);
        if ("hello server".equals(greeting)) {
            out.println("hello client");
        }
        else {
            out.println("unrecognised greeting");
        }
    }

    public void stop() throws IOException {
        in.close();
        out.close();
        clientSocket.close();
        serverSocket.close();
    }
    public static void main(String[] args) throws IOException {
	// TODO Auto-generated method stub
	System.out.println("Server đang lắng nghe tại cổng 6666");
	GreetServer server=new GreetServer();
        server.start(6666);
    }

}

3.2. Ví dụ code ở phía Client


import java.net.*;
import java.io.*;

public class GreetClient {
    private Socket clientSocket;
    private PrintWriter out;
    private BufferedReader in;
    public void startConnection(String ip, int port) throws UnknownHostException, IOException {
        clientSocket = new Socket(ip, port);
        out = new PrintWriter(clientSocket.getOutputStream(), true);
        in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
    }

    public String sendMessage(String msg) throws IOException {
        out.println(msg);
        String resp = in.readLine();
        System.out.println(resp);
        return resp;
    }

    public void stopConnection() throws IOException {
        in.close();
        out.close();
        clientSocket.close();
    }
	
    public static void main(String[] args) throws IOException {
	// TODO Auto-generated method stub
	GreetClient client = new GreetClient();
        client.startConnection("127.0.0.1", 6666);
        String response = client.sendMessage("hello server");
        System.out.println("Client đã nhận được message:"+response);
    }
}

Trong phần tới, chúng ta sẽ giải thích chi tiết từng phần giao tiếp sử dụng giao tiếp bằng Socket qua ví dụ này.

3.3. Cách làm việc của Socket

Theo định nghĩa, Socket là một điểm cuối (endpoint) của liên kết giao tiếp hai chiều giữa hai chương trình chạy trên các máy tính khác nhau trong mạng. Socket được liên kết với một cổng (port) để tầng Transport có thể xác định dữ liệu của ứng dụng này được gửi tới.

3.3.1. Server

Thông thường, server chạy trên một máy tính cố định trên mạng và có một socket được gắn với một cổng cố định. Trong ví dụ trên, cả client chạy trên cùng máy tính và kết nối tới cổng 6666.


ServerSocket serverSocket = new ServerSocket(6666);

Server sẽ đợi, lắng nghe ở socket để client tạo một yêu cầu kết nối. Điều này xảy ra ở dòng kế tiếp:


Socket clientSocket = serverSocket.accept();

Máy chủ gọi phương thức accept(), nó sẽ chặn cho đến khi client đưa ra yêu cầu kết nối với nó.

Nếu mọi thứ diễn ra tốt đẹp, Server chấp nhận kết nối. Sau khi chấp nhận, Server nhận một socket mới, clientSocket, được liên kết tới cùng cổng cục bộ là 6666 và cũng có endpoint truy cập từ xa tới địa chỉ và cổng của client.
Tại điểm này, một đối tượng Socket mới đặt server một kết nối trực tiếp với client, chúng ta có thể truy cập các luồng output và input để ghi và nhận message tới và từ client tương ứng.


PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

Từ đây server có khả năng trao đổi message với client liên tục cho đến khi socket đóng các luồng của nó.

Tuy nhiên, trong ví dụ này, server chỉ có thể gửi phản hồi lời chào trước khi đóng kết nối, điều này có nghĩa là nếu chúng ta chạy lại, kết nối sẽ bị từ chối.

Để cho phép giao tiếp liên tục, chúng ta sẽ phải đọc từ luồng đầu vào bên trong vòng lặp while và chỉ thoát ra khi máy khách gửi yêu cầu kết thúc, chúng ta sẽ hiệu chỉnh trong phần sau.

Với mỗi client mới, server cần một socket mới được trả về bởi lời gọi accept(). serverSocket được sử dụng để tiếp tục lắng nghe các yêu cầu kết nối khi các client kết nối tới.

3.3.2. Client

Client phải biết tên máy chủ hoặc IP của máy chủ đang chạy và cổng (port) mà máy chủ đang lắng nghe.

Để thực hiện yêu cầu kết nối, client sẽ cố gắng kết nối máy chủ và cổng của mở trên máy chủ:


Socket clientSocket = new Socket("127.0.0.1", 6666);

Đoạn code trên sẽ tạo một socket mới khi server đã chấp nhận kết nối, nếu không, sẽ nhận được exception bị từ chối kết nối. Khi được tạo thành công, chúng có thể lấy các luồng input và output để giao tiếp với server:


PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

Luồng input của client được kết nối với luồng output của server, giống như luồng input của server được kết nối với luồng output của client.

3.4. Giao tiếp liên tục

Chúng ta sẽ cập nhật code để server lắng nghe liên tục các client tới, giống như chúng ta thực thi một chương trình chat server.
Chúng ta sẽ tạo một vòng lặp while tiếp tục giữ luồng input server cho các message tới.
Chúng ta sẽ tạo một lớp EchoServer.java nhiệm vụ sẽ gửi lại bất kỳ message nào nó nhận được từ client:


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

public class EchoServer {
    public void start(int port) {
        serverSocket = new ServerSocket(port);
        clientSocket = serverSocket.accept();
        out = new PrintWriter(clientSocket.getOutputStream(), true);
        in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        
        String inputLine;
        while ((inputLine = in.readLine()) != null) {
        if (".".equals(inputLine)) {
            out.println("good bye");
            break;
         }
         out.println(inputLine);
    }
}

Server trong trường hợp này kết thúc lắng nghe khi nhận được ký tự dấu chấm (“.”).
Các phương thức khác của EchoServer giống như GreetServer.
Các bạn hoàn thiện chương trình EchoClient tương tự như GreetClient và chạy thử chương trình.

3.5. Server với nhiều Client

Cải tiến code trên để server có thể phục vụ nhiều client và nhiều yêu cầu đồng thời cùng lúc.


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

public class EchoMultiServer {
    private ServerSocket serverSocket;

    public void start(int port) {
        serverSocket = new ServerSocket(port);
        while (true)
            new EchoClientHandler(serverSocket.accept()).start();
    }

    public void stop() {
        serverSocket.close();
    }

    private static class EchoClientHandler extends Thread {
        private Socket clientSocket;
        private PrintWriter out;
        private BufferedReader in;

        public EchoClientHandler(Socket socket) {
            this.clientSocket = socket;
        }

        public void run() {
            out = new PrintWriter(clientSocket.getOutputStream(), true);
            in = new BufferedReader(
              new InputStreamReader(clientSocket.getInputStream()));
            
            String inputLine;
            while ((inputLine = in.readLine()) != null) {
                if (".".equals(inputLine)) {
                    out.println("bye");
                    break;
                }
                out.println(inputLine);
            }

            in.close();
            out.close();
            clientSocket.close();
    }
}

Chú ý rằng chúng ta gọi phương thức accept bên trong vòng lặp while. Mỗi khi vùng lặp while thực thi, nó sẽ khoá lời gọi accept cho tới khi một client mới được kết nối, rồi một luồng handler thực hiện. EchoClientHandler được tạo cho client này.
Những gì xảy ra bên trong thread này giống như chúng ta đã làm trong EchoServer ở ví dụ trước mà chúng ta chỉ thực hiện với một client.
EchoMultiServer ủy quyền công việc này cho EchoClientHandler để nó có thể tiếp tục lắng nghe nhiều client hơn trong vòng lặp while.
Chúng ta vẫn sử dụng EchoClient để chạy thử kết nối tới server. Chúng ta sẽ tạo nhiều client để gửi và nhận nhiều message từ server.
Code tham khảo EchoClient:


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;


public class EchoClient {
	
	Socket clientSocket;
	PrintWriter out;
	BufferedReader in;
	public void startConnection(String ip, int port) throws UnknownHostException, IOException
	{
		clientSocket = new Socket(ip, port);
		out = new PrintWriter(clientSocket.getOutputStream(),true);
		in= new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
	}
	
	public String sendMessage(String msg) throws IOException
	{
		out.println(msg);
		String resp = in.readLine();
		return resp;
	}
	
	public void stopConnection() throws IOException
	{
		in.close();
		out.close();
		clientSocket.close();
	}

	public static void main(String[] args) throws UnknownHostException, IOException {
		// TODO Auto-generated method stub
		EchoClient client = new EchoClient();
		client.startConnection("127.0.0.1", 6666);
		String inputLine;
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 
		while ((inputLine = br.readLine()) != null) {
			System.err.println("Client gửi:" + inputLine);
			String resp = client.sendMessage(inputLine);
			System.out.println(resp);
		}
	}

}

3.6. Bài tập

3.6.1. Bài tập 1

Viết chương trình Chat-Room:

  • Server sẽ lắng nghe tại một địa chỉ x.x.x.x và cổng 3000.
  • Các client kết nối đến server và có thể gửi message, thông tin message gửi sẽ bao gồm: tên client + nội dung message + thời gian gửi.
  • Khi một client gửi message thì các client khác cũng sẽ nhận được.
  • Khi một client thoát khỏi phòng chat hoặc join vào phòng chat, sẽ có thông báo gửi đến các client khác.
  • Client gõ từ “bye” để thoát khỏi phòng chat
  • Ứng dụng sẽ gồm hai phần, client và server có thể chạy độc lập trên các máy tính khác nhau.

3.6.2. Code tham khảo bài tập 1

a. ChatServer.java

import java.io.*;
import java.net.*;
import java.util.*;
 
/**
 * Chương trình Chat Server.
 * Ấn Ctrl + C để kết thúc chương trình.
 *
 * @timoday.edu.vn
 */
public class ChatServer {
    private int port;
    //Lưu danh sách các tài khoản người dùng
    private Set<String> userNames = new HashSet<>();
    private Set<UserThead> userThreads = new HashSet<>();
 
    public ChatServer(int port) {
        this.port = port;
    }
 
    public void execute() {
        try (ServerSocket serverSocket = new ServerSocket(port)) {
 
            System.out.println("Chat Server is listening on port " + port);
 
            while (true) {
                Socket socket = serverSocket.accept();
                System.out.println("New user connected");
 
                UserThread newUser = new UserThread(socket, this);
                userThreads.add(newUser);
                newUser.start();
 
            }
 
        } catch (IOException ex) {
            System.out.println("Error in the server: " + ex.getMessage());
            ex.printStackTrace();
        }
    }
 
    public static void main(String[] args) {
        if (args.length < 1) {
            System.out.println("Syntax: java ChatServer ");
            System.exit(0);
        }
 
        int port = Integer.parseInt(args[0]);
 
        ChatServer server = new ChatServer(port);
        server.execute();
    }
 
    /**
     * Gửi các message từ 1 người dùng tới các người dùng khác - gửi dạng quảng bá
     */
    void broadcast(String message, UserThread excludeUser) {
        for (UserThread aUser : userThreads) {
            if (aUser != excludeUser) {
                aUser.sendMessage(message);
            }
        }
    }
 
    /**
     * Lưu username của client mới được kết nối.
     */
    void addUserName(String userName) {
        userNames.add(userName);
    }
 
    /**
     * Khi client ngắt kết nối, sẽ bỏ username và UserThread
     */
    void removeUser(String userName, UserThread aUser) {
        boolean removed = userNames.remove(userName);
        if (removed) {
            userThreads.remove(aUser);
            System.out.println("The user " + userName + " quitted");
        }
    }
    /**
     * Lấy danh sách các user đang kết nối
     */
    Set getUserNames() {
        return this.userNames;
    }
 
    /**
     * Trả về true nếu có user đã kết nối
     */
    boolean hasUsers() {
        return !this.userNames.isEmpty();
    }
}
b. UserThread.java

import java.io.*;
import java.net.*;
import java.util.*;
 
/**
 * Thead này điều khiển kết nối cho mỗi client kết nối tới, để cho phép server có thể điều khiển nhiều client tại cùng thời điểm
 *
 * @timoday.edu.vn
 */
public class UserThread extends Thread {
    private Socket socket;
    private ChatServer server;
    private PrintWriter writer;
 
    public UserThread(Socket socket, ChatServer server) {
        this.socket = socket;
        this.server = server;
    }
 
    public void run() {
        try {
            InputStream input = socket.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(input));
 
            OutputStream output = socket.getOutputStream();
            writer = new PrintWriter(output, true);
 
            printUsers();
 
            String userName = reader.readLine();
            server.addUserName(userName);
 
            String serverMessage = "New user connected: " + userName;
            server.broadcast(serverMessage, this);
 
            String clientMessage;
 
            do {
                clientMessage = reader.readLine();
                serverMessage = "[" + userName + "]: " + clientMessage;
                server.broadcast(serverMessage, this);
 
            } while (!clientMessage.equals("bye"));
 
            server.removeUser(userName, this);
            socket.close();
 
            serverMessage = userName + " has quitted.";
            server.broadcast(serverMessage, this);
 
        } catch (IOException ex) {
            System.out.println("Error in UserThread: " + ex.getMessage());
            ex.printStackTrace();
        }
    }
 
    /**
     * In ra danh sách các user online.
     */
    void printUsers() {
        if (server.hasUsers()) {
            writer.println("Connected users: " + server.getUserNames());
        } else {
            writer.println("No other users connected");
        }
    }
 
    /**
     * Gửi message tới client.
     */
    void sendMessage(String message) {
        writer.println(message);
    }
}
c. ChatClient.java

import java.net.*;
import java.io.*;
 
/**
 * Chương trình chat Client.
 * Đánh 'bye' để kết thúc chương trình.
 *
 * @timoday.edu.vn
 */
public class ChatClient {
    private String hostname;
    private int port;
    private String userName;
 
    public ChatClient(String hostname, int port) {
        this.hostname = hostname;
        this.port = port;
    }
 
    public void execute() {
        try {
            Socket socket = new Socket(hostname, port);
 
            System.out.println("Connected to the chat server");
 
            new ReadThread(socket, this).start();
            new WriteThread(socket, this).start();
 
        } catch (UnknownHostException ex) {
            System.out.println("Server not found: " + ex.getMessage());
        } catch (IOException ex) {
            System.out.println("I/O Error: " + ex.getMessage());
        }
 
    }
 
    void setUserName(String userName) {
        this.userName = userName;
    }
 
    String getUserName() {
        return this.userName;
    }
 
 
    public static void main(String[] args) {
        if (args.length < 2) return;
 
        String hostname = args[0];
        int port = Integer.parseInt(args[1]);
 
        ChatClient client = new ChatClient(hostname, port);
        client.execute();
    }
}
d. ReadThread.java

import java.io.*;
import java.net.*;
 
/**
 * Đây là thread làm nhiệm vụ đọc dữ liệu đầu vào từ server và in kết quả ra console.
 * Nó sẽ chạy một vòng lặp vô hạn đến khi client ngắt kết nối tới server
 *
 * @timoday.edu.vn
 */
public class ReadThread extends Thread {
    private BufferedReader reader;
    private Socket socket;
    private ChatClient client;
 
    public ReadThread(Socket socket, ChatClient client) {
        this.socket = socket;
        this.client = client;
 
        try {
            InputStream input = socket.getInputStream();
            reader = new BufferedReader(new InputStreamReader(input));
        } catch (IOException ex) {
            System.out.println("Error getting input stream: " + ex.getMessage());
            ex.printStackTrace();
        }
    }
 
    public void run() {
        while (true) {
            try {
                String response = reader.readLine();
                System.out.println("\n" + response);
 
                // prints the username after displaying the server's message
                if (client.getUserName() != null) {
                    System.out.print("[" + client.getUserName() + "]: ");
                }
            } catch (IOException ex) {
                System.out.println("Error reading from server: " + ex.getMessage());
                ex.printStackTrace();
                break;
            }
        }
    }
}
e. WriteThread.java

import java.io.*;
import java.net.*;
 
/**
 * Thread này chịu trách nhiệm đọc dữ liệu input từ người dùng và gửi tới server
 * Nó chạy một vòng lặp vô hạn cho đến khi người dùng đánh 'bye' để thoát.
 *
 * @timoday.edu.vn
 */
public class WriteThread extends Thread {
    private PrintWriter writer;
    private Socket socket;
    private ChatClient client;
 
    public WriteThread(Socket socket, ChatClient client) {
        this.socket = socket;
        this.client = client;
 
        try {
            OutputStream output = socket.getOutputStream();
            writer = new PrintWriter(output, true);
        } catch (IOException ex) {
            System.out.println("Error getting output stream: " + ex.getMessage());
            ex.printStackTrace();
        }
    }
 
    public void run() {
 
        Console console = System.console();
 
        String userName = console.readLine("\nEnter your name: ");
        client.setUserName(userName);
        writer.println(userName);
 
        String text;
 
        do {
            text = console.readLine("[" + userName + "]: ");
            writer.println(text);
 
        } while (!text.equals("bye"));
 
        try {
            socket.close();
        } catch (IOException ex) {
 
            System.out.println("Error writing to server: " + ex.getMessage());
        }
    }
}

4. Lập trình Socket sử dụng giao thức UDP

DatagramPacket DatagramSocket là hai class chính được sử dụng để triển khai ứng dụng client/server sử dụng giao thức UDP. DatagramPacket là một nơi chứa dữ liệu và DatagramSocket là một cơ chế gửi và nhận các DatagramPacket.

4.1. DatagramPacket

Trong giao thức UDP, dữ liệu truyền đi được đóng gói trong các đơn vị gọi là datagram. Một datagram là độc lập, nó chứa mesage gửi qua mạng với đích đến, thời gian đến và nội dung không được đảm bảo. Trong Java, DatagramPacket đại diện cho một datagram.
Bạn có thể tạo một đối tượg DatagramPacket bằng việc sử dụng các hàm khởi tạo sau:

  • DatagramPacket(byte[] buf, int length)
  • DatagramPacket(byte[] buf, int length, InetAddress address, int port)

Như bạn thấy,dữ liệu trong form là một mảng kiểu byte. Hàm khởi tạo thứ nhất được sử dụng để tạo một DatagramPacket được nhận.
Hàm khởi tạo thứ hại tạo một DatagramPacket được gửi, vì vậy bạn cần chỉ định một địa chỉ và cổng đích của của máy chủ đích.
Tham số length chỉ định số lượng mảng byte được sử dụng, thường là độ dài của mảng (buf.length).
Cũng có thể sử dụng các hàm khởi dựng khác mà cho phép bạn chị định offset trong mảng byte hoặc sử dụng một SocketAddress:

  • DatagramPacket(byte[] buf, int offset, int length)
  • DatagramPacket(byte[] buf, int offset, int length, SocketAddress address)

Ngoài ra, DatagramPacket cung cấp các phương thức getset cho address, data và port number. Xem thêm DatagramPacket Javadoc.

4.2. DatagramSocket

Bạn sử dụng DatagramSocket để gửi và nhận các DatagramPacket. DatagramSocket đại diện cho một kết nối UDP giữa hai máy tính trong mạng.
Trong Java, chúng ta sử dụng DatagramSocket cho cả client và server, mà không có class riêng cho client và server giống như TCP sockets.
Vì vậy bạn tạo một đối tượng DatagramSocket để thiết lập một kết nối UDP cho gửi và nhận datagram, với việc sử dụng các hàm khởi dụng sau:

  • DatagramSocket()
  • DatagramSocket(int port)
  • DatagramSocket(int port, InetAddress laddr)

Hàm khởi dựng đầu tiên không có tham số được sử dụng để tạo một client mà gắn với một port tuỳ ý.
Hàm khởi dựng thứ hai được sử dụng để tạo một server mà gắn với một port chỉ định để các client biết để kết nối tới.
Và hàm khởi dụng thứ ba gắn một server tới một địa chỉ IP cụ thể (trong trường hợp máy tính có nhiều địa chỉ IP).
Các hàm khởi dựng này có thể bắn ra SocketException nếu socket không được mở hoặc socket không thể gắn với một port hoặc một địa chỉ nào đó. Vì vậy bạn xử lý các ngoại lệ hoặc bắn lại các ngoại lệ đã được kiểm tra này.

Các phương thức quan trọng của DatagramSocket:

  • send(DatagramPacket p): gửi một gói datagram.
  • receive(DatagramPacket p): nhận một gói datagram.
  • setSoTimeout(int timeout): thiết lập thời gian timeout theo đơn vị milliseconds, giới hợn thời gian chờ khi nhận dữ liệu. Nếu hết thời gian chờ một ngoại lệ SocketTimeoutException sẽ được phát sinh.
  • close(): đóng socket.

Các phương thức này có thể ném ra các ngoại lệ IOException, PortUnreachableException, SocketTimeoutException… vì vậy bạn có thể bắt các ngoại lệ này hoặc xử lý chúng.
Xem chi tiết DatagramSocket.

4.3. Ví dụ code phía Server


/**
 * Tạo một UDP server lắng nghe tại cổng 6789
 * Chạy một vòng lặp vô hạn để đợi các client kết nối tới.
 *
 * @timoday.edu.vn
 */
import java.net.*;
import java.io.*;
public class UPPServer{
	public static void main(String args[]){ 
	DatagramSocket aSocket = null;
	try{
		aSocket = new DatagramSocket(6789);
		byte[] buffer = new byte[1000];
 		while(true){
 		   DatagramPacket request = new DatagramPacket(buffer, buffer.length);
  		   aSocket.receive(request);
  		   System.out.println("Server nhận được:"+new String(request.getData()));
                   DatagramPacket reply = new DatagramPacket(request.getData(), 
		   	request.getLength(), request.getAddress(), request.getPort());
    		   aSocket.send(reply);
		}
	 }
	catch (SocketException e){System.out.println("Lỗi Socket: " + e.getMessage());}
	catch (IOException e) {System.out.println("Lỗi IO: " + e.getMessage());}
	finally {if(aSocket != null) aSocket.close();}
  }
}

4.4. Ví dụ code phía Client


import java.net.*;
import java.io.*;
/**
 * Tạo một UDP client kết nối tới server theo địa chỉ cụ thể và cổng 6789
 * Địa chỉ và message được truyền vào theo đối số truyền vào khi chạy
 * Ví dụ chạy chương trình UDPClient localhost "Xin chao ban"
 * @timoday.edu.vn
 */
public class UDPClient{
    public static void main(String args[]){ 
    	// Truyền vào nội dung message gửi và địa chỉ ip hoăc tên server
    	DatagramSocket aSocket = null;
    	try {
			aSocket = new DatagramSocket();    
			byte [] m = args[1].getBytes();
			InetAddress aHost = InetAddress.getByName(args[0]);
			int serverPort = 6789;		                                                 
			DatagramPacket request = new DatagramPacket(m,  m.length, aHost, serverPort);
			aSocket.send(request);			                        
			byte[] buffer = new byte[1000];
			DatagramPacket reply = new DatagramPacket(buffer, buffer.length);	
			aSocket.receive(reply);
			System.out.println("Client nhận được: " + new String(reply.getData()));	
    	}
    	catch (SocketException e){System.out.println("Lỗi Socket: " + e.getMessage());}
    	catch (IOException e){System.out.println("Lỗi IO: " + e.getMessage());}
    	finally {if(aSocket != null) aSocket.close();}
   } 
}

5. Kết luận

Trong hướng dẫn này, chúng tôi đã tập trung vào phần giới thiệu về lập trình socket qua TCP/IP và viết một ứng dụng Client/Server đơn giản bằng Java.

6. Xem thêm nội dung bài giảng

Có thể bạn sẽ thích…

Trả lời

EnglishVietnamese