C HƯƠNG HƯƠNG
a. Sử dụng Socket ở Client
- Dưới đây là một chương trình ngắn minh hoạ việc sử dụng Socket ở Client. Trong ví dụ, client thiết lập một connection với Echo server (port = 7), ở máy ResearchCC dùng lớp Socket trong thư viện API của Java. Client nhập một hàng từ standard input stream, gửi cho Echo server. Echo server nhận
được, gửi trả hàng này về lại client. Client đọc hàng này và xuất lại ra màn hình.
- Việc sử dụng Socket trong chương trình Client của phần mềm này có đôi chút phức tạp hơn nhưng những ý tưởng chính là hoàn toàn giống nhau.
import java.io.*; import java.net.*;
public class EchoTest {
public static void main(String[] args) { Socket echoSocket = null;
DataOutputStream os = null; DataInputStream is = null;
DataInputStream stdIn = new DataInputStream(System.in); try {
echoSocket = new Socket("ResearchCC", 7);
os = new DataOutputStream(echoSocket.getOutputStream()); is = new DataInputStream(echoSocket.getInputStream()); } catch (UnknownHostException e) {
System.err.println("Don't know about host: ResearchCC"); } catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to: ResearchCC"); }
if (echoSocket != null && os != null && is != null) { try {
String userInput;
while ((userInput = stdIn.readLine()) != null) { os.writeBytes(userInput); os.writeByte('\n'); System.out.println("echo: " + is.readLine()); } os.close(); is.close(); echoSocket.close(); } catch (IOException e) {
System.err.println("I/O failed on the connection to: ResearchCC"); }
} } }
Giải thích chương trình trên:
- Ba hàng sau trong khối try của phương thức main() buộc phải có. Chúng thiết lập socket connetion giữa client-server và mở input, outputstream trên socket tạo ra:
echoSocket = new Socket("ResearchCC", 7);
os = new DataOutputStream(echoSocket.getOutputStream()); is = new DataInputStream(echoSocket.getInputStream());
Hàng đầu tạo ra một đối tượng Socket, đặt tên là echoSocket. Socket constructor được sử dụng ở đây yêu cầu tên máy và port number mà ta muốn
connect tới. Chương trình ví dụ dùng host name ResearchCC. Ðối số thứ hai là port number. Port 7 là port mà Echo server listen.
Hàng thứ hai và thứ ba mở một output stream và một input stream trên socket vừa thiết lập. EchoTest đơn thuần chỉ cần write tới output stream và read từ input stream để truyền dữ liệu với server thông qua socket. Nếu bạn chưa quen với các stream trong Java, bạn có thể xem thêm phần các Stream cũng trong đề tài này.
- Phần kế đọc từ standard input stream của EchoTest một hàng mỗi lần. EchoTest write ngay input text (theo sau bởi một newline character) tới output stream:
String userInput;
while ((userInput = stdIn.readLine()) != null) { os.writeBytes(userInput);
os.writeByte('\n');
System.out.println("echo: " + is.readLine()); }
- Hàng cuối trong vòng lặp while đọc một hàng từ input stream. Phương thức readLine() block cho tới khi server echo thông tin trở về cho EchoTest. Khi readLine() return, EchoTest in hàng thông tin ra standard output. Vòng lặp while tiếp tục-- EchoTest đọc input từ user, gửi nó cho Echo server, nhận trả lời từ server, và hiển thị nó-- cho tới khi user đánh vào một end-of-input character.
- Khi user đánh vào một end-of-input character, vòng lặp while kết thúc, chương trình tiếp tục thực thi ba hàng kế:
os.close(); is.close();
echoSocket.close();
- Ba hàng code này đóng các input, output stream, rồi đóng socket connection tới server. Thứ tự thực hiện ở đây rất quan trọng, ta nên đóng các stream kết nối với một socket trước khi đóng chính socket đó.
- Nhìn chung, các bước cần tiến hành để dùng socket ở phía client như sau:
1. Mở một socket.
2. Mở input stream và outputstream ứng vớ socket đó.
3. Read và write tới stream tuỳ thuộc vào nghi thức của server 4. Ðóng các stream.
5. Ðóng socket.
- Chỉ có bước ba là khác nhau giữa các client, do dựa vào server. Các bước còn lại hầu như giống nhau.
b. Sử dụng Socket ở Server
- Chương trình Server bắt đầu bằng việc tạo ra một instance của lớp ServerSocket để listen một port được đặc tả. Khi hiện thực một chương trình Server, ta nên chọn một port mà không được dành sẵn cho các dịch vụ khác:
try {
serverSocket = new ServerSocket(4444); } catch (IOException e) {
System.exit(1); }
- Bước kế tiếp, Server accept một connection request từ một client:
Socket clientSocket = null; try {
clientSocket = serverSocket.accept(); } catch (IOException e) {
System.out.println("Accept failed: " + 4444 + ", " + e); System.exit(1);
}
- Sau khi sinh ra socket ứng với client yêu cầu connect,server dựa vào socket và các input, output stream ứng với socket này để thực hiện việc read, write dữ liệu. Ðiều này hoàn toàn giống như cách thức đã mô tả ở phần sử dụng soclet ở Client được mô tả ở phần trên. Cụ thể là các việc sau:
1. Mở một input và output stream ứng với socket. 2. Read và write tới socket.
- Trong ví dụ, có nhiều client đồng thời đưa ra các connection request với server tại port mà server listen (port 4444). Có hai cách để giải quyết vấn đề này:
1. Các connection request được xếp hàng, và Server phải accept các connection tuần tự
2. Phục vụ các connection request đồng thời bằng việc dùng các thread-- Mỗi thread xử lý một connection
Ví dụ đã chọn cách thứ hai để hiện thực vì nó hợp lý hơn: mọi user cần phải được xử lý bình đẳng như nhau.
Giải thuật cho phần này như sau:
while (true) {
accept a connection;
create a thread to deal with the client;
end while
Thread được sinh ra sẽ read và write tới connection ứng với connection đó khi cần thiết.