Hướng dẫn lập trình Java Socket
Xem thêm các chuyên mục:
- Thông thường, một chương trình server chạy trên một máy tính cụ thể, chương trình này có một ổ cắm (Server Socket), ổ cắm được ràng buộc bởi cổng (Port number) cụ thể. Các chương trình phục vụ (Server program) chỉ chờ đợi, lắng nghe tại ổ cắm (Server Socket) các Client để thực hiện một yêu cầu kết nối.
- Các Client biết tên máy của máy tính mà trên đó chương trình chủ (server) đang chạy và số cổng mà chương trình chủ lắng nghe. Để thực hiện một yêu cầu kết nối, Client cố gắng tạo ra cuộc gặp với máy chủ trên máy tính của chương trình chủ và cổng. Các Client cũng cần phải tự định danh chính nó với server để gắn với một cổng địa phương cái sẽ được sử dụng trong suốt quá trình kết nối này, thông thường nó được gán bởi hệ điều hành.



Các Client và Server có thể giao tiếp bằng cách ghi hay đọc từ ổ cắm (Socket) của chúng.

Định nghĩa:
Một Socket là một điểm cuối của một giao tiếp 2 chiều giữa hai chương trình chạy trên mạng. Socket được giàng buộc với một cổng (con số cụ thể) để các tầng TCP (TCP Layer) có thể định danh ứng dụng mà dữ liệu sẽ được gửi tới.
package org.o7planning.tutorial.socket; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; public class SimpleServerProgram { public static void main(String args[]) { ServerSocket listener = null; String line; BufferedReader is; BufferedWriter os; Socket socketOfServer = null; // Mở một ServerSocket tại cổng 9999. // Chú ý bạn không thể chọn cổng nhỏ hơn 1023 nếu không là người dùng // đặc quyền (privileged users (root)). try { listener = new ServerSocket(9999); } catch (IOException e) { System.out.println(e); System.exit(1); } try { System.out.println("Server is waiting to accept user..."); // Chấp nhận một yêu cầu kết nối từ phía Client. // Đồng thời nhận được một đối tượng Socket tại server. socketOfServer = listener.accept(); System.out.println("Accept a client!"); // Mở luồng vào ra trên Socket tại Server. is = new BufferedReader(new InputStreamReader(socketOfServer.getInputStream())); os = new BufferedWriter(new OutputStreamWriter(socketOfServer.getOutputStream())); // Nhận được dữ liệu từ người dùng và gửi lại trả lời. while (true) { // Đọc dữ liệu tới server (Do client gửi tới). line = is.readLine(); // Ghi vào luồng đầu ra của Socket tại Server. // (Nghĩa là gửi tới Client). os.write(">> " + line); // Kết thúc dòng os.newLine(); // Đẩy dữ liệu đi os.flush(); // Nếu người dùng gửi tới QUIT (Muốn kết thúc trò chuyện). if (line.equals("QUIT")) { os.write(">> OK"); os.newLine(); os.flush(); break; } } } catch (IOException e) { System.out.println(e); e.printStackTrace(); } System.out.println("Sever stopped!"); } }
package org.o7planning.tutorial.socket; import java.io.*; import java.net.*; public class SimpleClientDemo { public static void main(String[] args) { // Địa chỉ máy chủ. final String serverHost = "localhost"; Socket socketOfClient = null; BufferedWriter os = null; BufferedReader is = null; try { // Gửi yêu cầu kết nối tới Server đang lắng nghe // trên máy 'localhost' cổng 9999. socketOfClient = new Socket(serverHost, 9999); // Tạo luồng đầu ra tại client (Gửi dữ liệu tới server) os = new BufferedWriter(new OutputStreamWriter(socketOfClient.getOutputStream())); // Luồng đầu vào tại Client (Nhận dữ liệu từ server). is = new BufferedReader(new InputStreamReader(socketOfClient.getInputStream())); } catch (UnknownHostException e) { System.err.println("Don't know about host " + serverHost); return; } catch (IOException e) { System.err.println("Couldn't get I/O for the connection to " + serverHost); return; } try { // Ghi dữ liệu vào luồng đầu ra của Socket tại Client. os.write("HELO"); os.newLine(); // kết thúc dòng os.flush(); // đẩy dữ liệu đi. os.write("I am Tom Cat"); os.newLine(); os.flush(); os.write("QUIT"); os.newLine(); os.flush(); // Đọc dữ liệu trả lời từ phía server // Bằng cách đọc luồng đầu vào của Socket tại Client. String responseLine; while ((responseLine = is.readLine()) != null) { System.out.println("Server: " + responseLine); if (responseLine.indexOf("OK") != -1) { break; } } os.close(); is.close(); socketOfClient.close(); } catch (UnknownHostException e) { System.err.println("Trying to connect to unknown host: " + e); } catch (IOException e) { System.err.println("IOException: " + e); } } }
Chạy ví dụ:


package org.o7planning.tutorial.socketthread; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; public class ServerProgram { public static void main(String args[]) throws IOException { ServerSocket listener = null; System.out.println("Server is waiting to accept user..."); int clientNumber = 0; // Mở một ServerSocket tại cổng 7777. // Chú ý bạn không thể chọn cổng nhỏ hơn 1023 nếu không là người dùng // đặc quyền (privileged users (root)). try { listener = new ServerSocket(7777); } catch (IOException e) { System.out.println(e); System.exit(1); } try { while (true) { // Chấp nhận một yêu cầu kết nối từ phía Client. // Đồng thời nhận được một đối tượng Socket tại server. Socket socketOfServer = listener.accept(); new ServiceThread(socketOfServer, clientNumber++).start(); } } finally { listener.close(); } } private static void log(String message) { System.out.println(message); } private static class ServiceThread extends Thread { private int clientNumber; private Socket socketOfServer; public ServiceThread(Socket socketOfServer, int clientNumber) { this.clientNumber = clientNumber; this.socketOfServer = socketOfServer; // Log log("New connection with client# " + this.clientNumber + " at " + socketOfServer); } @Override public void run() { try { // Mở luồng vào ra trên Socket tại Server. BufferedReader is = new BufferedReader(new InputStreamReader(socketOfServer.getInputStream())); BufferedWriter os = new BufferedWriter(new OutputStreamWriter(socketOfServer.getOutputStream())); while (true) { // Đọc dữ liệu tới server (Do client gửi tới). String line = is.readLine(); // Ghi vào luồng đầu ra của Socket tại Server. // (Nghĩa là gửi tới Client). os.write(">> " + line); // Kết thúc dòng os.newLine(); // Đẩy dữ liệu đi os.flush(); // Nếu người dùng gửi tới QUIT (Muốn kết thúc trò chuyện). if (line.equals("QUIT")) { os.write(">> OK"); os.newLine(); os.flush(); break; } } } catch (IOException e) { System.out.println(e); e.printStackTrace(); } } } }
package org.o7planning.tutorial.socketthread; import java.io.*; import java.net.*; import java.util.Date; public class ClientDemo { public static void main(String[] args) { // Địa chỉ máy chủ. final String serverHost = "localhost"; Socket socketOfClient = null; BufferedWriter os = null; BufferedReader is = null; try { // Gửi yêu cầu kết nối tới Server đang lắng nghe // trên máy 'localhost' cổng 7777. socketOfClient = new Socket(serverHost, 7777); // Tạo luồng đầu ra tại client (Gửi dữ liệu tới server) os = new BufferedWriter(new OutputStreamWriter(socketOfClient.getOutputStream())); // Luồng đầu vào tại Client (Nhận dữ liệu từ server). is = new BufferedReader(new InputStreamReader(socketOfClient.getInputStream())); } catch (UnknownHostException e) { System.err.println("Don't know about host " + serverHost); return; } catch (IOException e) { System.err.println("Couldn't get I/O for the connection to " + serverHost); return; } try { // Ghi dữ liệu vào luồng đầu ra của Socket tại Client. os.write("HELO! now is " + new Date()); os.newLine(); // kết thúc dòng os.flush(); // đẩy dữ liệu đi. os.write("I am Tom Cat"); os.newLine(); os.flush(); os.write("QUIT"); os.newLine(); os.flush(); // Đọc dữ liệu trả lời từ phía server // Bằng cách đọc luồng đầu vào của Socket tại Client. String responseLine; while ((responseLine = is.readLine()) != null) { System.out.println("Server: " + responseLine); if (responseLine.indexOf("OK") != -1) { break; } } os.close(); is.close(); socketOfClient.close(); } catch (UnknownHostException e) { System.err.println("Trying to connect to unknown host: " + e); } catch (IOException e) { System.err.println("IOException: " + e); } } }
TT | Phương thức và mô tả |
---|---|
1 | public ServerSocket(int port) throws IOException
Tạo một đối tượng Server Socket giàng buộc với một cổng cụ thể. Một ngoại lệ sẽ được ném ra nếu cổng đó đã bị giàng buộc (Sử dung) bởi một chương trình khác. |
2 | public ServerSocket(int port, int backlog) throws IOException
Tương tự như cấu tử trên, tham số backlog định rõ có bao nhiêu client đến để lưu trữ trên hàng đợi. |
3 | public ServerSocket(int port, int backlog, InetAddress address) throws IOException
Tương tự như cấu tử trên, tham số InetAddress chỉ rõ địa chỉ IP địa phương sẽ được nối (bind) tới. InetAddress được sử dụng cho các máy chủ có thể có nhiều địa chỉ IP, cho phép các máy chủ để xác định các địa chỉ IP của nó để chấp nhận yêu cầu của client. |
4 | public ServerSocket() throws IOException
Tạo một Server Socket chưa định rõ cổng, địa chỉ. Khi sử dụng cấu tử này, sử dụng phương thức bind(..) khi bạn sẵn sàng để nối với địa chỉ, cổng cụ thể. |
TT | Phương thức và mô tả |
---|---|
1 | public int getLocalPort()
Trả về cổng mà Server Socket đang lắng nghe. Phương thức này rất có ích, nếu bạn đưa vào giá trị cổng bằng 0 trong cấu tử, nghĩa là nói với server tự tìm một cổng phù hợp, sau đó sử dụng phương thức này để lấy ra giá trị thực. |
2 | public Socket accept() throws IOException
Đợi một yêu cầu kết nối từ client. Phương thức này sẽ khóa ứng dụng cho tới khi có một yêu cầu kết nối từ client đến trên cổng cụ thể hoặc hết thời gian chờ (Time-out), giả sử rằng thời gian time-out được thiết lập sử dụng phương thức setSoTimeout(). Ngược lại method sẽ bị khóa vô thời hạn. |
3 | public void setSoTimeout(int timeout)
Sét thời gian chờ tối đa (time-out) nghĩa là thời gian Server Socket sẽ chờ yêu cầu kết nối từ người dùng trong quá trình accept(). |
4 | public void bind(SocketAddress host, int backlog)
Nối Server Socket tới một server cụ thể có cổng định sẵn trong đối tượng SocketAddress. Sử dụng phương thức này nếu bạn khởi tạo ServerSocket sử dụng cấu tử mặc định (Không tham số). |
TT | Cấu tử và mô tả |
---|---|
1 | public Socket(String host, int port) throws UnknownHostException, IOException.
Cấu tử này tạo Socket kết nối tới Server cụ thể tại cổng xác định trong tham số, Nếu nó không ném ra ngoại lệ, nghĩa là việc kết nối thành công, client đã kết nối với server. |
2 | public Socket(InetAddress host, int port) throws IOException
Cấu tử này giống hệt với các nhà xây dựng trước đó, ngoại trừ Server được biểu thị bằng một đối tượng InetAddress. |
3 | public Socket(String host, int port, InetAddress localAddress, int localPort) throws IOException.
Kết nối tới host, port cụ thể, tạo ra một Socket trên host địa phương, và cổng địa phương được chỉ định trong tham số. |
4 | public Socket(InetAddress host, int port, InetAddress localAddress, int localPort) throws IOException.
Cấu tử này giống hệt với cấu tử trên, ngoại trừ server được biểu thị bằng một đối tượng InetAddress thay vì một String |
5 | public Socket()
Tạo một Socket chưa kết nối. Sử dụng phương thức connect() để kết nối socket này tới server. |
TT | Phương thức và mô tả |
---|---|
1 | public void connect(SocketAddress host, int timeout) throws IOException
Phương thức này kết nối socket này tới host chỉ định. Phương thức này cần thiết chỉ khi bạn khởi tạo một đối tượng Socket thông qua cấu tử mặc định (Không tham số). |
2 | public InetAddress getInetAddress()
Phương thức này trả về địa chỉ của máy tính mà socket này kết nối tới. |
3 | public int getPort()
Trả về cổng giàng buộc tới máy tính từ xa. |
4 | public int getLocalPort()
Trả về cổng socket là ràng buộc để trên máy địa phương. |
5 | public SocketAddress getRemoteSocketAddress()
Trả về địa chỉ của socket từ xa (remote socket). |
6 | public InputStream getInputStream() throws IOException
Trả về luồng đầu vào của Socket. Luồng đầu vào này được kết nối với luồng đầu ra của Socket từ xa (remote socket). |
7 | public OutputStream getOutputStream() throws IOException
Trả về luồng đầu ra của Socket. Luồng đầu ra này kết nối với luồng đầu vào của Socket từ xa. |
8 | public void close() throws IOException
Đóng socket, nghĩa là làm cho Socket này không còn khả năng trò chuyện với máy kia. |
TT | Phương thức và mô tả |
---|---|
1 | static InetAddress getByAddress(byte[] addr)
Trả về đối tượng InetAddress cho bởi địa chỉ IP thô. |
2 | static InetAddress getByAddress(String host, byte[] addr)
Trả về đối tượng InetAddress dựa trên tên máy chủ được cung cấp và địa chỉ IP. |
3 | static InetAddress getByName(String host)
Xác định địa chỉ IP của host, cho bởi tên host. |
4 | String getHostAddress()
Trả về địa chỉ IP. |
5 | String getHostName()
Trả về host name |
6 | static InetAddress getLocalHost()
Trả về địa chỉ địa phương. |
7 | String toString()
Chuyển đối tượng thành String. |