Saturday, June 9, 2007

Chat Program - Học Java - Bài 6

Xem code của file: CreateNewChatClient.java
Đây có thể xem là lớp quan trọng nhất của phần Server.
Nhiệm vụ của lớp này là tạo mới một bộ lưu trữ cho Client kết nối đến, thực hiện các chức năng của phần Server, kết nối các Client với nhau và chạy song song với các Thread khác để đảm bảo không bị trễ khi các Client muốn làm việc với nhau.
7. implements Runnable : Dòng này nhằm thừa kế lại lớp Runnable của Java để có thể chạy song song lớp này.
8. private boolean finished = false; Đánh dấu xem lớp có cần dừng hay không, nếu dừng chương trình sẽ chấm dứt luôn Thread này.
9. private Socket client; Dùng để lưu một bản copy của Client kết nối đến
10. private String myNick; Tên của Client kết nối đến
11. private String myPass;
12. private boolean loginned=false; Đánh dấu xem đã login chưa, nếu đã login các chức năng tương ứng sẽ được kích hoạt

Để hiểu được hai biến này bạn phải biết chút ít về luồng nhập và xuất trong Java.
14. BufferedReader inStream; Luồng vào, nó chịu trách nhiệm kết nối đến luồng vào của lớp và đọc dữ liệu
16. BufferedWriter outStream; Luồng ra, nó sẽ xuất dữ liệu ra luồng này, để cho lớp khác đọc dữ liệu, hoặc chính nó.
Ví dụ: Chúng ta có 2 lớp: 1 Lớp A từ phía Client kết nối đến Server với giao thưc là TCP (không dùng UDP, nếu không sẽ mất kết nối), ở Server nó sẽ tạo ra 1 lớp tương ứng với lớp A của Client và copy toàn bộ thông tin của lớp A đó (hiển nhiên có thông tin luồng vào và ra). Khi lớp A gửi thông tin đến luồng ra của nó, thì phía Server nó sẽ nhận được thông tin ở phía luồng vào và ngược lại. Đọc tiếp phần dưới.
19. public CreateNewChatClient(Socket newClient) : newClient đây chính là lớp Socket của Client kết nối đến, nó sẽ được lớp chính ChatServer truyền vào để lấy dữ liệu.
20->24 : Copy và lấy luồng nhập/xuất
Tiếp theo, kéo xuống dòng 216, bạn sẽ thấy một hàm public void run() : Hàm này là của lớp Runnable, được cài đặt lại, hàm này có trách nhiệm làm cho lớp này chạy song song.
219. while (!finished) : Lặp hoài không dừng, nhằm mục đích lấy dữ liệu ở luồng vào của lớp, nó sẽ dừng khi phía Client tắt cái của sổ chat (:D).
Bây giờ có lẽ bạn sẽ hỏi một câu: Tại sao phải rườm ra như vậy, dùng thẳng lệnh lặp mãi mãi này được rồi, tạo Thread gì cho mệt, câu trả lời sẽ là: Nếu bạn chạy vĩnh viễn mà không dùng Thread thì chương trình sẽ treo ngay. Còn nếu bạn không chạy vĩnh viễn thì nếu được bạn chỉ lấy được dữ liệu một lần ở luồng vào mà thôi (sau khi lấy xong lớp sẽ kết thúc luôn). Tốt nhất bạn nên viết thử một đoạn code để test 2 trường hợp này để rõ hơn (chú ý khi lặp vĩnh viễn thì nhớ cài Thread nhé, không thì treo máy đó).
220. Dòng này để đọc dữ liệu ở dòng vào nếu không có nó sẽ trả về là null.
222. Dòng này là gửi dữ liệu đến hàm processMessage để xử lý (bạn cũng có thể xử lý ở ngay trong này nhưng sẽ rất lộn xộn).
141. private void processMessage(String str) : Hàm xử lý các thông điệp, biến str sẽ lưu thông điệp cân xử lý nó theo một cấu trúc nhất định.
Cấu trúc: Mã_Thông_Điệp,Nội_dung_1,Nội_dung_2 Bạn có thể thiêt kế đoạn này thành một lớp cho nó pro (:D).
Các thông điệp trong chương trình
1. Thông điệp tạo nick mới: 1, user, pass
2. Thông điepj login: 2, user, pass
3. Thông điệp yêu cầu kết nối đến Client khác: 3, tên client muốn kết nối
4. Thông điệp gửi message đến Client đang kết nối: 5, tên nick, thông điệp
5. Thông điệp yêu cầu lấy tên tất cả các nick có trên Server: 6
6. Thông điệp báo cho Server biết là Client đã thoát: 7
Xem đoạn code của hàm rồi đọc phần tiếp, hãy khoan rê chuột đến hàm tương ứng để xem
48. private void createNewNick(String newNick, String pass) : Hàm này hỗ trợ cho thông điệp 1, chẳng có gì khó nó đọc file Nick.txt xem đã có nick chưa, nếu chưa thì tạo mới, bạn có thể thay bằng CSDL cho pro, vì mục đich của mình là chương trình chat nên mình chỉ dùng text thôi.
87. private boolean login(String nick, String pass) : Hàm này hỗ trợ thông điệp 2, tương tự hàm createNewNick, Nếu thành công nó sẽ cập nhật 2 giá trị nick, pass và gửi trả lại thông điệp 21 cho Client, thông điệp này báo rằng đã login thành công ngược lại là thông điệp 20.
123. private void connectOtherClient(String nickB)
: Hàm này hỗ trợ thông điệp 3, có một xí phức tạp
124. sendMessage(nickB, "3"+myNick)
; nickB là nick của Client khác mà Client này muốn kết nối, cấu trúc yêu cầu là "3"+myNick.
134. sendMessage : 135. Kiểm tra xem Client này đã login chưa, nếu chưa thì không cho phép, 136. Tìm nickB trong bộ lưu trữ của Server xem có không, 137. Nếu tồn tại nickB thì gửi thông điệp yêu cầu chat đến nó nó dùng hàm này để gửi(tự gửi tới nó) sendMessageToMe, message có cấu trúc là 3nickA, chú ý điểm này nhé lệnh của nó là nC.sendMessageToMe(message); chứ không phải nó gọi hàm sendMessageToMe ở dòng 28 đâu đấy.
28. public void sendMessageToMe(String message) : Hàm này chỉ có nhiệm vụ là ghi chuỗi message vào luồng ra để cho dòng 220 trong hàm run đọc.
129. private void chatMessage(String nickB, String message) : Tương tự hàm sendMessage nhưng thông điệp của nó là 5, dùng để gửi câu chat.
181 và 203 chắc không cần giải thích thêm.