176
Trang 1 MỤC LỤC CH ƯƠNG 1: T ỔNG QUAN VỀ HỆ THỐNG TRUYỀN THÔNG 4 1.1. Một số giao thức c ơ b ản của hệ thống truyền thông 4 1.1.1. Giao thức H.323 4 1.1.2. Giao thức SIP 8 1.1.3. Chuẩn nén âm thanh và hình ảnh 11 1.2. Truyền thông thời gian thực 12 1.2.1. Các khái niệm và đ ịnh nghĩa đ ư ợc sử dụng trong RTP: 13 1.2.2. Thứ tự byte, alignment và đ ịnh dạng thời gian 15 1.3. Các giao thức truyền thông trên mạng Internet 15 1.4. Các mô hình ứng dụng trên nền giao thức TCP/IP: mô hình client – server, mô hình P2P. 16 1.4.1. Bộ giao thức TCP/IP : 16 1.4.2. Dịch vụ mạng (Net service) : là một ch ương tr ình ứng dụng thực hiện một tác vụ nào đó tr ên hệ thống mạng. 17 1.4.3. Mô hình Client-Server 17 1.4.3.1. Nhiệm vụ của Client và Server 18 1.4.3.2. Mô hình Client-Server của dịch vụ WEB 19 1.4.3.3. Các chế đ ộ giao tiếp 20 1.4.4. Mô hình Peer to Peer 22 1.4.4.1. Phân loại mạng đ ồng đ ẳng: 22 1.4.4.2. Ưu th ế của mạng đ ồng đ ẳng 23 1.5. C ơ ch ế giao tiếp liên quá trình (InterProccess Comunication) 23 1.6. Một số mô hình hệ thống truyền thông: 25 1.6.1. Hệ thống trả lời tự đ ộng IVR 25 1.6.1.1. Khái niệm. 25 1.6.1.2. Các dịch vụ đi ển hình của IVR. 26 1.6.1.3. Các ưu đi ểm của hệ thống IVR. 27 1.6.1.4. CallXML-CCXML 27 1.6.2. Hộp th ư tho ại (voicemail) 28 1.6.3. Dịch vụ tin nhắn SMS 29 1.6.4. Voice over IP 31 1.6.4.1. Giới thiệu về VoIP: 31 1.6.4.2. Ưu đi ểm của VoIP so với PSTN: 31 1.6.4.2. Các hình thức truyền thoại trên mạng IP 33 1.6.4.3. Nguyên tắc và mô hình hoạt đ ộng của VoIP 33 1.6.4.4. Các nghi thức đ ư ợc sử dụng trong hệ thống VoIP 34 1.6.4.5. Các vấn đ ề liên quan đ ến chất l ư ợng dịch vụ 36 CH ƯƠNG 2 : L ẬP TRÌNH JAVA 38 2.1. Lập trình h ư ớng đ ối t ư ợng và lập trình có cấu trúc 38 2.1.1. Lập trình h ư ớng chức n ăng 39 2.1.2. Lập trình h ư ớng đ ối t ư ợng 41 2.2. Lịch sử phát triển của ngôn ngữ java 41 2.3. Máy ảo java và trình biên dịch 43 2.4. Biên soạn ch ương tr ình bằng phần mềm Notepad của Ms Windows 44 2.4.1. Soạn thảo ch ương tr ình nguồn: 44

MỤC LỤC - ect.ictu.edu.vnect.ictu.edu.vn/attachments/article/215/Thiet ke he thong truyen thong... · Cổng kết nối H.323 kết nối mạng H.323 với mạng không phải

  • Upload
    dobao

  • View
    215

  • Download
    0

Embed Size (px)

Citation preview

Trang 1

MỤC LỤC

CHƯƠNG 1: TỔNG QUAN VỀ HỆ THỐNG TRUYỀN THÔNG 41.1. Một số giao thức cơ bản của hệ thống truyền thông 4

1.1.1. Giao thức H.323 41.1.2. Giao thức SIP 81.1.3. Chuẩn nén âm thanh và hình ảnh 11

1.2. Truyền thông thời gian thực 121.2.1. Các khái niệm và định nghĩa được sử dụng trong RTP: 131.2.2. Thứ tự byte, alignment và định dạng thời gian 15

1.3. Các giao thức truyền thông trên mạng Internet 151.4. Các mô hình ứng dụng trên nền giao thức TCP/IP: mô hình client – server, mô hìnhP2P. 16

1.4.1. Bộ giao thức TCP/IP : 161.4.2. Dịch vụ mạng (Net service) : là một chương trình ứng dụng thực hiện một tácvụ nào đó trên hệ thống mạng. 171.4.3. Mô hình Client-Server 17

1.4.3.1. Nhiệm vụ của Client và Server 181.4.3.2. Mô hình Client-Server của dịch vụ WEB 191.4.3.3. Các chế độ giao tiếp 20

1.4.4. Mô hình Peer to Peer 221.4.4.1. Phân loại mạng đồng đẳng: 221.4.4.2. Ưu thế của mạng đồng đẳng 23

1.5. Cơ chế giao tiếp liên quá trình (InterProccess Comunication) 231.6. Một số mô hình hệ thống truyền thông: 25

1.6.1. Hệ thống trả lời tự động IVR 251.6.1.1. Khái niệm. 251.6.1.2. Các dịch vụ điển hình của IVR. 261.6.1.3. Các ưu điểm của hệ thống IVR. 271.6.1.4. CallXML-CCXML 27

1.6.2. Hộp thư thoại (voicemail) 281.6.3. Dịch vụ tin nhắn SMS 291.6.4. Voice over IP 31

1.6.4.1. Giới thiệu về VoIP: 311.6.4.2. Ưu điểm của VoIP so với PSTN: 311.6.4.2. Các hình thức truyền thoại trên mạng IP 331.6.4.3. Nguyên tắc và mô hình hoạt động của VoIP 331.6.4.4. Các nghi thức được sử dụng trong hệ thống VoIP 341.6.4.5. Các vấn đề liên quan đến chất lượng dịch vụ 36

CHƯƠNG 2 : LẬP TRÌNH JAVA 382.1. Lập trình hướng đối tượng và lập trình có cấu trúc 38

2.1.1. Lập trình hướng chức năng 392.1.2. Lập trình hướng đối tượng 41

2.2. Lịch sử phát triển của ngôn ngữ java 412.3. Máy ảo java và trình biên dịch 432.4. Biên soạn chương trình bằng phần mềm Notepad của Ms Windows 44

2.4.1. Soạn thảo chương trình nguồn: 44

Trang 2

2.4.2. Biên dịch và thực thi chương trình 442.5. Các khái niệm cơ bản của ngôn ngữ java 45

2.5.1. Đối tượng 452.5.2. Lớp đối tượng 462.5.3. Trìu tượng hóa dữ liệu 462.5.4. Bao bọc và che dấu thông tin 472.5.5. Sự mở rộng, kế thừa giữa các lớp 482.5.6. Đa xạ ( tương ứng bội) và nạp chồng 492.5.7. Liên kết động 502.5.8. Truyền thông điệp 512.5.9. Các ưu điểm của lập trình hướng đối ượng 51

2.6. Các kiểu dữ liệu 522.6.1. Kiểu dữ liệu cơ sở 522.6.2. Quy ước đặt tên lớp, tên đối tượng, tên phương thức 53

2.7. Các từ khóa trong java 542.8. Chú thích trong chương trình java (Comment) 562.9. Các phép toán cơ bản 562.10. Cấu trúc một chương trình java kiểu ứng dụng độc lập 562.11. Các cấu trúc điều khiển 58

2.11.1. Lệnh rẽ nhánh if 582.11.2. Lệnh switch 592.11.3. Lệnh while 602.11.4. Lệnh do - while 612.11.5. Lệnh for 612.11.6. Lệnh break 622.11.7. Lệnh continue 632.11.9. Phép toán ? 632.11.10. Đọc đối số của chương trình 642.11.11. Đổi chuỗi thành số 642.11.12. Ngoại lệ (EXCEPTION) 65

2.12. Lớp và các thành phần của lớp đối tượng 672.12.1. Định nghĩa lớp 672.12.1. Định nghĩa hàm thành phần 672.12.3. Nạp chồng các thành phần của hàm 682.12.4. Viết đè các hàm thành phần và cơ chế che bóng của các biến 68

2.13. Phạm vi và các thuộc tính kiểm soát truy nhập các thành phần của lớp 714.13.1. Phạm vi của các thành phần 712.13.2. Các thuộc tính kiểm soát truy cập các thành phần của lớp 73

2.14. Các kiểu ứng dụng 742.15. Làm việc với các stream 75

2.15.1. Lớp java.io.InputStream 762.15.2. Lớp java.io.OutputStream 782.15.3. Nhập chuỗi từ một InputStream 792.15.4. Xuất chuỗi ra một OutputStream 80

2.16. Lập trình luồng (thread) 812.16.1. Các mức cài đặt luồng 82

2.16.1.1. Tiếp cận luồng ở mức người dùng 822.16.1.2. Tiếp cận luồng ở mức nhân hệ điều hành 83

2.16.2. Luồng trong java 83

Trang 3

2.16.2.1. Độ ưu tiên của luồng 862.16.3. Đồng bộ hóa giữa các luồng 87

2.17. Mô hình ứng dụng truyền thông qua socket và RPC 872.17.1. Mô hình ứng dụng socket 872.17.2. Mô hình ứng dụng RPC (Remote Procedure Call) 88

2.17.2.1. Giới thiệu 882.17.2.2. Kiến trúc của chương trình Client-Server cài đặt theo cơ chế lời gọi thủ tụcxa 892.17.2.3. Kích hoạt phương thức xa (RMI- Remote Method Invocation ) 902.17.2.4. Kiến trúc của chương trình 912.17.2.5. Các cơ chế liên quan trong một ứng dụng đối tượng phân tán 922.17.2.6. Cơ chế vận hành của của một ứng dụng Client-Server theo kiểu RMI 932.17.2.7. Các lớp hỗ trợ chương trình theo kiểu Client-Server trong Java 942.17.2.8. Xây dựng một ứng dụng phân tán với RMI 95

Chương 3: LẬP TRÌNH TRUYỀN THÔNG QUA SOCKET102

3.1. Đặc điểm của socket 1023.2. Socket hoạt động ở chế độ có nối kết 104

3.2.1. Đặc điểm socket hoạt động ở chế độ có nối kết 1043.2.2. Thí dụ minh họa 107

3.2.2.1. Xây dựng chương trình Client ở chế độ có nối kết 1073.2.2.2. Xây dựng chương trình Server ở chế độ có nối kết 110

3.3. Socket hoạt động ở chế độ không có nối kết 1153.3.1. Đặc điểm socket hoạt động ở chế độ không có nối kết 1153.3.2. Thí dụ minh họa 116

CHƯƠNG 4: LẬP TRÌNH GIAO TIẾP VỚI CỔNG MÁY TÍNH 1234.1. Lập trình cổng LPT 123

4.1.1. Đặc điểm cổng LPT 1234.1.2. Các gói và các lớp liên quan đến lập trình cổng LPT 1254.1.3. Thí dụ minh họa 125

4.2. Lập trình cổng COM 1284.2.1. Đặc điểm cổng COM 1284.2.2. Các gói và các lớp liên quan đến lập trình cổng COM 1314.2.3. Thí dụ minh họa 131

CHƯƠNG 5: THIẾT KẾ HỆ THỐNG TRUYỀN THÔNG 1375.1. Điều khiển hệ thống trong java 137

5.1.1. Các lớp và các gọi hỗ trợ lập trình hệ thống trong java 1375.1.2. Phát hiện vị trí của chuột 1395.1.4. Phát hiện sự kiện chuột hoặc phím được nhấn 140

5.2. Mô hình ứng dụng truyền thông giữa PC-PC 1415.3. Mô hình ứng dụng truyền thông giữa PC – Phone 1415.4. Mô hình ứng dụng truyền thông giữa PC – PSTN - Phone 1415.5. Thí dụ minh họa 141

Trang 4

CHƯƠNG 1: TỔNG QUAN VỀ HỆ THỐNG TRUYỀN THÔNG

1.1. Một số giao thức cơ bản của hệ thống truyền thông

1.1.1. Giao thức H.323

- H.323 là chuẩn mở được ITU-T (Telecommunication Standardization

Sector of the International Telecommunications Union) phát triển cho việc điều

khiển cuộc gọi ngang hàng, dựa trên cơ sở của H.320 và ISDN Q.931.

- H.323 là một cấu trúc chặt chẽ, phức tạp và phù hợp với việc thực thi các đặc

tính thoại truyền thống.

- Tiêu chuẩn H.323 thiết kế cho truyền audio, video và dữ liệu qua mạng IP

bao gồm Internet.

- Tiêu chuẩn H.323 bao gồm báo hiệu và điều khiển cuộc gọi, truyền và điều

khiển đa phương tiện và điều khiển băng thông cho hội nghị điểm - điểm và đa

điểm.

- Tiêu chuẩn H.323 bao gồm các giao thức được liệt kê trong bảng 2.1

Các thành phần cơ bản của hệ thống H.323:

Các thành phần cơ bản trong hệ thống H.323 được mô tả trong hình 2.1 dưới

đây. Bao gồm các đầu cuối, cổng kết nối, thiết bị điều khiển cổng nối (gatekeeper)

và khối điều khiển đa điểm (MCU)

Trang 5

Hình 1.1. Các thành phần của mạng H323

a. Thiết bị đầu cuối:

- Đầu cuối cung cấp thông tin điểm điểm và đa điểm với các đầu cuối khác.

- Đầu cuối H.323 bao gồm các khối như điều khiển hệ thống, khối truyền tải

phương tiện, mã hoá audio và giao diện với mạng IP.

- Phần thiết kế bị tùy chọn có thể là mã hoá video và thiết bị truyền dữ liệu.

b. Cổng kết nối(Gateway):

Cổng kết nối cung cấp giao diện giữa hai mạng khác nhau.

Cổng kết nối H.323 kết nối mạng H.323 với mạng không phải H.323 như

PSTN. Cổng kết nối chuyển đổi giữa audio, video và các định dạng truyền dữ liệu

cũng như các giao thức và hệ thống thông tin.

Cổng kết nối chỉ cần thiết khi phải kết nối mạng phi H.323, do đó khồng cần

thiết khi kết nối giữa 2 thiết bị đầu cuối H.323.

Thiết bị điều khiển cổng kết nối (Gatekeeper):

Thiết bị điều khiển cổng kết nối là tùy chọn, có thể sử dụng hoặc không.

Thiết bị điều khiển cổng nối cung cấp các dịch vụ trước khi diễn ra cuộc gọi và dịch

vụ điều khiển cuộc gọi cho các điểm cuối H.323. Tuy nhiên nếu thiết bị điều khiển

cổng nối có mặt trong mạng nó sẽ có nhiệm vụ: biên dịch địa chỉ, điều khiển chấp

nhận, điều khiển băng thông và quản lý vùng.

Trang 6

Các chức năng tùy chọn của thiết bị điều khiển cổng nối bao gồm: báo hiệu

điều khiển cuộc gọi, xác thực cuộc gọi, quản lý băng thông, quản lý cuộc gọi.

Khối điều khiển đa điểm (MCU)

Khối điều khiển đa điểm là điểm cuối (endpoint) hỗ trợ hội nghị ba thành

viên hoặc nhiều hơn. MCU điển hình bao gồm bộ điều khiển đa điểm (MC) và một

hoặc nhiều bộ xử lý đa điểm (MP).

MC xử lý điều khiển và báo hiệu để hỗ trợ hội nghị trong khi MP nhận dữ

liệu audio, video và luồng dữ liệu, xử lý và phân bố chúng đến các điểm cuối trong

thành viên hội nghị đa điểm.

Bộ giao thức H.323 bao gồm nhiều giao thức. Bộ giao thức hỗ trợ chấp nhận

cuộc gọi, thiết lập trạng thái, giải phóng, luồng phương tiện và các bản tin trong hệ

thống H.323. Các giao thức được hỗ trợ cả cơ chế truyền đưa ra gói tin cậy và

không tin cậy qua mạng IP như minh hoạ trong hình 2.3.

Trang 7

Hình 1.2. Bộ giao thức H323

Bộ giao thức H.323 bao gồm 3 vùng điều khiển :

+ Báo hiệu đăng ký, thừa nhận và trạng thái (RAS) : báo hiệu RAS cung cấp

điều khiển trước cuộc gọi trong mạng thiết bị điều khiển cổng nối H.323

+ Báo hiệu điều khiển cuộc gọi (H.225) : dựa trên khuyến nghị H.225 của

ITU-T mà nó chỉ ra việc sử dụng các bản tin bản hiệu Q.931. Kênh điều

khiển cuộc gọi tin cậy TCP được tao ra trên mạng IP với mã cổng là 1720

+ Điều khiển và truyền tải thông tin Media (H.245 và RTP/RTCP) : H.245

xử lý các bản tin từ đầu đến cuối giữa các điểm cuối H.323. Thủ tục giao

thức H.245 thiết lập kênh cho truyền audio, video dữ liệu và thông tin kênh

điều khiển. Truyền đa phương tiện trong H.323 được cung cấp bởi RTP và

RTCP.

Trình tự thiết lập cuộc gọi:

Nếu xem xét một cách chi tiết thì cuộc gọi giữa hai đầu cuối H.323 được

thiết lập như hình 2.4

Trang 8

Hình 1.3. Trình tự thiết lập cuộc gọi

Trước hết cả hai phải được đăng ký tại thiết bị điều khiển cổng kết nối

Đầu cuối A gửi yêu cầu tới thiết bị điều khiển cổng kết nối đề nghị thiết lập cuộc

gọi.

Thiết bị điều khiển cổng nối gửi cho đầu A thông tin cần thiết về đầu cuối B

Đầu cuối A gửi bản tin SETUP tới đầu cuối B.

Đầu cuối B trả lời bằng bản tin Call Proceeding và đồng thời liên lạc với thiết

bị điều khiển cổng nối để xác nhận quyền thiết lập cuộc gọi.

Đầu cuối B gửi bản tin cảnh báo và kết nối.

Hai đầu cuối trao đổi một số bản tin H.245 để xác định chủ tớ, khả năng xử lý

của đầu cuối và thiết lập kết nối RTP.

Trang 9

Đây là trường hợp cuộc gọi điểm điểm đơn giản nhất, khi mà báo hiệu cuộc

gọi không được định tuyến tới thiết bị điều khiển cổng nối. H.323 hỗ trợ nhiều kịch

bản thiết lập cuộc gọi khác.

H.323 là hệ thống ghép lai được xây dựng từ các thiết bị tập trung thông minh

như : thiết bị điều khiển cổng nối, MCU, cổng kết nối và điểm cuối. Mặc dù chuẩn

H.323 trong phiên bản gần đây nhất có phần toàn diện hơn song vấn đề vẫn nảy

sinh, như thời gian thiết lập cuộc gọi dài, quá nhiều chức năng thiết bị điều khiển

cổng nối phải thực hiện và khả nằng mở rộng khi sử dụng kiểu báo hiệu cuộc gọi

định tuyến qua thiết bị điều khiển cổng nối (GKRCS).

Khi cần sử dụng cổng kết nối dung lượng lớn để kết nối mạng PSTN, người ta

sẽ sử dụng giao thức cổng đơn giản (SGCP : Simple Gateway Control Protocol) và

giao thức điều khiển cổng phương tiện (MGCP : Media Gateway Control Protocol)

để thay thế giao thức cho cổng kết nối H.323. Các hệ thống điều khiển cuộc gọi này

có vẻ hiệu quả hơn, đáp ứng nhu cầu của các nhà cung cấp cỡ lớn

Cũng vậy, giao thức khởi tạo phiên SIP (Session Initiation Protocol) có thể giải

quyết một số tồn tại của H.323 và nó khả năng sẽ thay thế H.323

1.1.2. Giao thức SIP

Giao thức khởi tạo phiên SIP (Session Initiation Protocol) là một giao thức

điều khiển và đã được chuẩn hóa bởi IETF. Nhiệm vụ của nó là thiết lập, hiệu chỉnh

và xóa các phiên làm việc giữa người dùng. Các phiên làm việc cũng có thể là hội

nghị đa phương tiên, Cuộc gọi điện thoại điểm-điểm,….SIP được sử dụng kết hợp

với các chuẩn giao thức IETF khác như là SAP, SDP và MGCP (MEGACO) để

cung cấp một lĩnh vực rộng hơn cho các dịch vụ VoIP.

Cấu trúc của SIP tương tự với cấu trúc của HTTP (giao thức client-server). Nó

bao gồm các yêu cầu được gởi đến từ người sử dụng SIP client đến SIP server.

Server xử lý các yêu cầu và đáp ứng đến client. Một thông điệp yêu cầu, cùng

với các thông điệp đáp ứng tạo nên sự thực thi SIP.

SIP là một công cụ hỗ trợ hấp dẫn đối với điện thoại IP vì các lý do sau:

+ Nó có thể hoạt động vô trạng thái hoặc có trạng thái. Vì vậy, sự hoạt động vô

Trang 10

trang thái cung cấp sự mở rộng tốt do các server không phải duy trì thông tin về

trạng thái cuộc gọi một khi sự thực hiện (transaction) đã được xử lý.

+ Nó có thể sử dụng nhiều dạng hoặc cú pháp giao thức chuyển siêu văn bản HTTP

(Hypertext Transfer Protocol), vì vậy, nó cung cấp một các thuận lợi để hoạt động

trên các trình duyệt.

+ Bản tin SIP (nội dung bản tin) thì không rõ rang, nó có thể là bất cứ cú pháp

nào. Vì vậy, nó có thể được mô tả theo nhiều cách. Chẳng hạn, nó có thể được mô

tả với sự mở rộng thư Internet đa mục đích MINE (Multipurpose Internet Mail

Extension) hoặc ngôn ngữ đánh dấu mở rộng XML (Extensible Markup Language).

+Nó nhận dạng một người dùng với bộ định vị tài nguyên đồng nhất URL (Uniform

Resource Locator), vì vậy, nó cung cấp cho người dùng khả năng khởi tạo cuộc gọi

bằng cách nhấp vào một liên kết trên trang web.

Nói chung, SIP hỗ trợ các hoạt động chính sau:

- Định vị trí của người dùng.

- Định media cho phiên làm việc.

- Định sự sẵn sàng của người dùng để tham gia vào một phiên làm việc.

- Thiết lập cuộc gọi, chuyển cuộc gọi và kết thúc.

B. Cấu trúc của SIP:

Một khía cạnh khác biệt của SIP đối với các giao thức xử lý cuộc gọi IP khác

là nó không sử dụng bộ điều khiển Gateway. Nó không dùng khái niệm Gateway/

bộ điều khiển Gateway nhưng nó dựa vào mô hình client/server.

Server: là một chương trình ứng dụng chấp nhận các bản tin yêu cầu để phục vụ các

yêu cầu này và gửi trả các đáp ứng cho các yêu cầu đó. Server là Proxy, gửi lại

(redirect), UAS hoặc Registrar.

Proxy server: là một chương trình trung gian, hoạt động như là một server và

một client cho mục đích tạo các yêu cầu thay mặt cho các client khác. Các yêu cầu

được phục vụ bên trong hoặc truyền chúng đến các server khác.

Một proxy có thể dịch và nếu cần thiết, có thể tạo lại bản tin yêu cầu SIP trước

khi chuyển chúng đến server khác hoặc một UA. Trong trường hợp này trường Via

Trang 11

trong bản tin đáp ứng, yêu cầu chỉ ra các proxy trung gian tham gia vào tiến trình xử

lý yêu cầu.

Redirect server: là một server chấp nhận một yêu cầu SIP, ánh xạ địa chỉ

trong yêu cầu thành một địa chỉ mới và trả lại địa chỉ này trở về client. Không giống

như Proxy server, nó không khởi tạo một yêu cầu SIP và không chuyển các yêu cầu

đến các Server khác. Không giống như Server đại diện người dùng UAS, nó không

chấp nhận cuộc gọi.

Registrar: là một server chấp nhận yêu cầu REGISTER. Một Registrar được

xếp đặt với một Proxy hoặc một server gửi lại và có thể đưa ra các dịch vụ định vị.

Registrar được dùng để đăng ký các đối tượng SIP trong miền SIP và cập nhật vị trí

hiện tại của chúng. Một miền SIP thì tương tự với một vùng H.323.

UA (User Agent): là một ứng dụng chứa cả UAC (User Agent Client) và UAS.

+ UAC (User Agent Client): đây là phần người sử dụng được dùng để khởi tạo một

yêu cầu SIP tới server SIP hoặc UAS.

+UAS (User Agent Server): là một ứng dụng server giao tiếp với người dùng

khi yêu cầu SIP được chấp nhận và trả lại một đáp ứng đại diện cho người dùng.

Hình 1 trình bày hai thành phần chính của SIP: User Agent và SIP server. User

Agent là một điểm cuối giao tiếp với người dùng và hoạt động đại diện cho

người dùng. User Agent bao gồm hai phần chính: một giao thức client được biết

như là UAC và một giao thức server được biết như là UAS.

UAC khởi tạo cuộc gọi và UAS trả lời cuộc gọi.

Do User Agent chứa cả UAC và UAS nên SIP có thể hoạt động ngang hàng khi

sử dụng mô hình client/server.

Server SIP có hai loại: Proxy server và Redirect Server.Proxy server nhận một

yêu cầu từ client và quyết định server kế tiếp mà yêu cầu sẽ đi đến. Proxy này có

thể gửi yêu cầu đến một server khác, một Redirect server hoặc UAS.

Đáp ứng sẽ được truyền cùng đường với yêu cầu nhưng theo chiều ngược lại.

Proxy server hoạt động như là client và server. Redirect server sẽ không chuyển

yêu cầu nhưng sẽ chỉ định client tiếp xúc trực tiếp với server kế tiếp, đáp ứng gửi

Trang 12

lại client chứa địa chỉ của server kế tiếp. Nó không hoạt động được như là một

client, nó không chấp nhận cuộc gọi.

Hình 1.4. Proxy Server

Trang 13

Hình 1.5. Redirect Server

1.1.3. Chuẩn nén âm thanh và hình ảnh

Chuẩn H.320 là một bộ các chuẩn định nghĩa cho khả năng hoạt động của Hội

nghị trực tuyến sử dụng công nghệ mạng ISDN. Các chuẩn này định nghĩa quy luật

để thiết lập thông tin, chia gói tin, đường truyền đồng bộ và bộ ghép kênh ISDN. Bộ

chuẩn H.323 được phát triển từ chuẩn H320, bao gồm các chuẩn sau:

· Chuẩn mã hóa/giải mã tín hiệu Video :

- Chuẩn H.261: Chuẩn mã hóa/giải mã Video cho giải thông 64 Kbps. Chuẩn

này chỉ hỗ trợ các độ phân giải trung bình như QCIF và lên đến CIF

(704x576)

Trang 14

- Chuẩn H.263: Chuẩn mã hóa/giải mã Video xen kẽ cho thông tin có lỗi bít

thấp. Chuẩn H.263 giải quyết được việc thể hiện trực tiếp độ phân giải tự

nhiên (Như NTSC: 704x480, VGA : 640x480) và độ phân giải cao

- Chuẩn H.264: Là một chuẩn mã hóa/giải mã hình ảnh mới được phát triển

bởi sự liên kết của ITU và Motion Picture Experts Group (MPEG). H.264

cung cấp 1 kỹ xảo nén và giải nén hình các ảnh động mạnh mẽ hơn các

chuẩn được xây dựng trước đây. Khi truyền hình hình ảnh động, kỹ xảo này

đòi hỏi băng thông sử dụng thấp hơn rất nhiều so với các chuẩn hình ảnh

trước đây. Đối với Videoconferencing, H.264 chỉ đòi hỏi 50% băng thông so

với các chuẩn đó và cho hình ảnh có chất lượng cao hoàn toàn tương đương.

· Chuẩn mã hóa/giải mã tín hiệu Audio :

- Chuẩn G.711: Nén tín hiệu âm thanh cơ bản tại 48Kbps tới 64 Kbps. Kỹ

thuật điều chế mã xung nhịp thấp giống như sử dụng trong điện thoại thông

thường.

- Chuẩn G.722: Chất lượng audio cao hơn tại cùng một giải thông sử dụng

thêm các quá trình xử lý tinh xảo.

- G.723, G.723.1 : Nén Audio cho tốc độ 5.3 kbps và 6.4 Kbps .

- Chuẩn G.728: Chuẩn nén âm thanh ở tỉ lệ bít thấp -16 kbps.

- G.729: Nén Audio cho tốc độ 8 Kbps

· Chuẩn cung cấp chế độ điều khiển

- H.245: Trao đổi message điều khiển các cuộc gọi điểm đầu cuối (end to

end).

- H.225 là chuẩn bắt tay giữa các thiết bị H.323 và gatekeeper bao gồm việc

đăng ký phiên làm việc, chấp nhận, từ chối, tận dụng băng thông và các

thông tin trạng thái.

1.2. Truyền thông thời gian thực

Realtime Protocol (RTP) là một chuẩn Internet để truyền các luồng

thông tin giữa các thành phần tương tác trên mạng. RTP cung cấp các dịch vụ

về dữ liệu mang tính thời gian thực như video và audio. Thông thường các ứng

dụng chạy RTP dựa trên UDP để tận dụng khả năng multiplexing và kiểm lỗi.

Trang 15

RTP hỗ trợ việc truyền dữ liệu đến nhiều địa chỉ đích bằng cách dùng cơ chế

multicast nếu được hỗ trợ bởi hệ thống mạng.

RTP không có sẵn các cơ chế để đảm bảo việc truyền theo thời gian hay

các kỹ thuật về QoS mà dựa vào các dịch vụ ở lớp dưới để thực hiện những khả

năng này. RTP không đảm bảo an toàn hay thứ tự các packet khi truyền, số thứ

tự trong RTP packet cho phép bên nhận sắp xếp lại các packet theo thứ tự khi

truyền của bên gửi. Ngoài ra số thứ tự cũng có thể được tận dụng để xác định

vị trí thích hợp của một packet, ví dụ trong việc giải mã video, mà không cần

phải giải mã các packet theo thứ tự.

1.2.1. Các khái niệm và định nghĩa được sử dụng trong RTP:

RTP payload: Dữ liệu được chuyển trong RTP packet, ví dụ như các mẫu âm

thanh (audio samples ) hay các dữ liệu hình ảnh nén (compressed video data).

RTP packet: Một gói dữ liệu bao gồm RTP header, danh sách các nguồn

cung cấp (contributing sources) có thể rỗng và dữ liệu payload. Một số nghi thức

mạng nền có thể yêu cầu phải xác định cơ chế đóng gói cho RTP packet. Thông

thường một gói của nghi thức mạng nền chứa một RTP packet, nhưng cũng có thể

chứa nhiều tùy theo cơ chế đóng gói (encapsulation).

RTCP packet: Một gói điều khiển bao gồm phần header tương tự như của

RTP packet, phần còn lại là các thành phần có cấu trúc tùy thuộc loại của gói

RTCP. Thông thường nhiều gói RTCP được gởi cùng lúc như một gói RTCP tổng

hợp được chứa trong một gói của nghi thức mạng nền.

Transport address: Sự kết hợp của địa chỉ mạng và cổng (port) để xác định

một điểm cuối (endpoint) ở mức transport, ví dụ như một địa chỉ IP và cổng UDP.

Các packets được truyền từ địa chỉ nguồn đến địa chỉ đích.

RTP session: Là sự kết hợp của các thành phần tham gia trao đổi thông tin.

Đối với mỗi thành phần tham gia, phiên (session) được xác định bởi một cặp địa

chỉ truyền đích. Cặp địa chỉ đích này có thể là chung cho mọi thành phần tham gia

hoặc riêng cho từng thành phần. Trong một phiên đa phương tiện, mỗi phương tiện

được chuyển tải bởi một RTP session riêng cùng với các gói RTCP của nó. Các

Trang 16

phiên RTP khác nhau được phân biệt bởi các cặp ports và địa chỉ multicast.

Synchronization source (SSRC): Nguồn của luồng các gói RTP được xác

định bởi một số định danh 32 bit trong header của gói RTP để độc lập với địa chỉ

network. Mỗi gói từ nguồn đồng bộ (SSRC) có cùng một không gian về thời gian

và số thứ tự, do đó bên nhận có thể nhóm các gói để phát lại (playback). Một

nguồn đồng bộ có thể thay đổi định dạng dữ liệu của nó vào bất cứ lúc nào. Định

danh nguồn đồng bộ là một giá trị ngẫu nhiên, giá trị này mang ý nghĩa duy nhất

(không trùng lắp) trong một RTP session riêng biệt. Một thành viên tham gia hội

thảo không cần phải dùng cùng một định danh SSRC trong một phiên đa phương

tiện.

Contributing source (CSRC): Là nguồn của luồng các gói RTP đã góp phần

tạo nên luồng kết hợp thông qua một bộ trộn RTP (RTP mixer). Bộ trộn RTP chèn

một danh sách các định danh nguồn đồng bộ (SSRC identifier) của các nguồn vào

RTP header của một gói RTP. Danh sách này được gọi là danh sách CSRC.

End system: Là một ứng dụng có khả năng tạo ra các nội dung để truyền

trong các gói RTP, hay nhận và xử lý nội dung của gói RTP. Một endsystem có thể

hoạt động như một hoặc nhiều nguồn đồng bộ trong một phiên RTP riêng, nhưng

thường là một.

Mixer: Là một hệ thống trung gian nhận các gói RTP từ một hay nhiều

nguồn, có thể thay đổi định dạng dữ liệu rồi kết hợp các gói đó lại theo một cách

thức nào đó tạo thành một gói RTP mới và truyền đi. Vì sự phối hợp thời gian giữa

các nguồn có thể không hoàn toàn đồng bộ nên bộ trộn sẽ đồng bộ thời gian giữa

các nguồn và sau đó, luồng ra sẽ có một sự định thời của mixer. Do đó các gói

được tạo ra từ một mixer đều xác định mixer là nguồn đồng bộ.

Translator: Là một hệ thống trung gian có nhiệm vụ chuyển tiếp các gói RTP

mà không làm thay đổi các nguồn đồng bộ.

Monitor: Là một ứng dụng tiếp nhận các gói RTCP được gửi từ các thành

viên của một phiên RTP, báo cáo cụ thể sự tiếp nhận, ước lượng chất lượng của

dịch vụ hiện thời và dự đoán lỗi. Chức năng monitor thường được xây dựng trong

Trang 17

các ứng dụng tham gia trong phiên, hoặc cũng có thể được xây dựng như một ứng

dụng tách biệt, có thể là thành viên hoặc không và không gởi, nhận các gói dữ liệu

RTP. Chúng được gọi là những monitor tham gia thứ ba.

Non-RTP means: Là các nghi thức hay cơ chế có thể được dùng để thêm vàoRTP để làm tăng tính khả dụng của các dịch vụ.1.2.2. Thứ tự byte, alignment và định dạng thời gian

Tất cả các trường số nguyên đều được truyền theo thứ tự byte chuẩn trên

mạng, có nghĩa là byte dấu nằm trước. Các hằng số đều ở dạng thập phân trừ các

trường hợp đặc biệt.

Tất cả các dữ liệu trong header được sắp xếp theo độ dài tự nhiên của nó, ví

dụ: các trường 16 bit được đặt ở các vị trí chẵn, các trường 32 bit được đặt ở các

vị trí chia hết cho 4…Các octets nối thêm mang giá trị 0.

Giờ tuyệt đối được biểu diễn theo nghi thức NTP (Network Time

Protocol), tính theo giây kêt từ 0 giờ ngày 01/01/1900. Ta dùng một số không dấu

64 bit để biểu diễn, trong đó 32 bit đầu là phần nguyền và 32 bit sau là phần thập

phân. Một số trường có thể chỉ dùng 32 bit giữa do nhu cầu nén dữ liệu, nghĩa là 16

bit thấp của phần nguyên và 16 bit cao của phần thập phân

1.3. Các giao thức truyền thông trên mạng Internet

Giao thức giao tiếp hay còn gọi là Giao thức truyền thông, Giao thức liên

mạng, Giao thức tương tác, Giao thức trao đổi thông tin ( communication

protocol) - trong công nghệ thông tin gọi tắt là giao thức (protocol), tuy nhiên,

tránh nhầm với giao thức trong các ngành khác - là một tập hợp các quy tắc chuẩn

dành cho việc biểu diễn dữ liệu, phát tín hiệu, chứng thực và phát hiện lỗi dữ liệu -

những việc cần thiết để gửi thông tin qua các kênh truyền thông, nhờ đó mà các

máy tính (và các thiết bị) có thể kết nối và trao đổi thông tin với nhau.

Các giao thức truyền thông dành cho truyền thông tín hiệu số trong mạng máy

tính có nhiều tính năng để đảm bảo việc trao đổi dữ liệu một cách đáng tin cậy qua

một kênh truyền thông không hoàn hảo.

Có nhiều giao thức được sử dụng để giao tiếp hoặc truyền đạt thông tin trên

Internet, dưới đây là một số các giao thức tiêu biểu:

Trang 18

· TCP (Transmission Control Protocol): thiết lập kết nối giữa các máy tính để

truyền dữ liệu. Nó chia nhỏ dữ liệu ra thành những gói (packet) và đảm bảo

việc truyền dữ liệu thành công.

· IP (Internet Protocol): định tuyến (route) các gói dữ liệu khi chúng được

truyền qua Internet, đảm bảo dữ liệu sẽ đến đúng nơi cần nhận.

· HTTP (HyperText Transfer Protocol): cho phép trao đổi thông tin (chủ yếu ở

dạng siêu văn bản) qua Internet.

· FTP (File Transfer Protocol): cho phép trao đổi tập tin qua Internet.

· SMTP (Simple Mail Transfer Protocol): cho phép gởi các thông điệp thư

điện tử (e-mail) qua Internet.

· POP3 (Post Office Protocol, phiên bản 3): cho phép nhận các thông điệp thư

điện tử qua Internet.

· MIME (Multipurpose Internet Mail Extension): một mở rộng của giao thức

SMTP, cho phép gởi kèm các tập tin nhị phân, phim, nhạc, ... theo thư điện

tử.

· WAP (Wireless Application Protocol): cho phép trao đổi thông tin giữa các

thiết bị không dây, như điện thoại di động.

1.4. Các mô hình ứng dụng trên nền giao thức TCP/IP: mô hình client – server,

mô hình P2P.

1.4.1. Bộ giao thức TCP/IP :

Trang 19

Hình 1.5 Bộ giao thức TCP/IP

Người ta còn gọi mô hình này là mô hình OSI đơn giản. Các giao thức được sử

dụng trên mỗi tầng được qui định như sau: tầng 2 sử dụng giao thức IP, tầng 3 có

thể sử dụng giao thức TCP ở chế độ có nối kết hoặc UPD ở chế độ không nối kết.

Tầng 4 là tầng của các ứng dụng. Mỗi loại ứng dụng phải định nghĩa một giao thức

riêng để các thành phần trong ứng dụng trao đổi thông tin qua lại với nhau.

Một số ứng dụng phổ biến đã trở thành chuẩn của mạng Internet như:

· Ứng dụng Web: Sử dụng giao thức HTTP để tải các trang web từ Web Server

về Web Browser.

· Ứng dụng thưđiện tử: Sử dụng giao thức SMTP để chuyển tiếp mail gửi đi

đến Mail Server của người nhận và dùng giao thức POP3 hoặc IMAP để

nhận mail về cho người đọc.

· Ứng dụng truyền tải tập tin: Sử dụng giao thức FTP để tải (download) các tập

tin từ các FTP Server ở xa về máy người dùng hay ngược lại.

· . . . . .

Thông thường các tầng 1,2,3 và 4 được phát triển bởi các nhà sản xuất hệ điều

hành, nhà sản xuất các thiết bị phần cứng mạng. Chúng đảm nhận nhiệm vụ truyền

Trang 20

tải thông tin cho các quá trình trên tầng ứng dụng. Chúng cài đặt các cơ chế giao

tiếp liên quá trình để các quá trình trên tầng ứng dụng có thể truy xuất đến dịch vụ

truyền tải thông tin do chúng cung cấp. Trong khi đó, tầng 5 là nơi các nhà sản xuất

phần mềm khai thác để tạo ra các ứng dụng giải quyết các vấn đề khác nhau của

cuộc sống. Nó được xem như là tầng xử lý thông tin.

1.4.2. Dịch vụ mạng (Net service) : là một chương trình ứng dụng thực hiện

một tác vụ nào đó trên hệ thống mạng.

· Một số dịch vụ mạng phổ biến:

· Print service: In ấn trên mạng.

· File service: chia sẻ file, dữ liệu, chương trình…

· Web service: cung cấp dịch vụ web.

· Mail service: cung cấp dịch vụ thư tín điện tử.

Có nhiều mô hình để xây dựng dịch vụ mạng: mô hình Client – Server và mô

hình Peer to Peer

1.4.3. Mô hình Client-Server

Trong mô hình này, chương trình ứng dụng được chia thành 2 thành phần:

· Quá trình chuyên cung cấp một số phục vụ nào đó, chẳng hạn: phục vụ tập

tin, phục vụ máy in, phục vụ thư điện tử, phục vụ Web... Các quá trình này

được gọi là các trình phục vụ hay Server.

· Một số quá trình khác có yêu cầu sử dụng các dịch vụ do các server cung cấp

được gọi là các quá trình khách hàng hay Client. Việc giao tiếp giữa client và

server được thực hiện dưới hình thức trao đổi các thông điệp (Message). Để

được phục vụ, client sẽ gởi một thông điệp yêu cầu (Request Message) mô tả

về công việc muốn server thực hiện. Khi nhận được thông điệp yêu cầu,

server tiến hành phân tích để xác định công việc cần phải thực thi. Nếu việc

thực hiện yêu cầu này có sinh ra kết quả trả về, server sẽ gởi nó cho client

trong một thông điệp trả lời (Reply Message). Dạng thức (format) và ý nghĩa

của các thông điệp trao đổi giữa client và server được qui định rõ bởi giao

thức (protocol) của ứng dụng.

Trang 21

Hình 1.6. Mô hình Client-Server

1.4.3.1. Nhiệm vụ của Client và Server

1.4.3.2. Mô hình Client-Server của dịch vụ WEB

Trang 22

Dịch vụ web được tổ chức theo mô hình Client -Server, trong đó:

· Web server sẵn sàng cung cấp các trang web đang được lưu trữ trên đĩa cứng

cục bộ của mình.

· Web Client, còn gọi là các Browser, có nhu cầu nhận các trang web từ các

Web Server

· HTTP là giao thức trao đổi thông tin qua lại giữa Web client và Web Server.

· Thông điệp yêu cầu là một chuỗi có dạng sau: Command URL HTTP/Ver

\n\n

· Thông điệp trả lời có dạng sau: <HEADER>\n\n <CONTENT>

· Giả sử Client cần nhận trang Web ởđịa chỉ http://www.cit.ctu.edu.vn/, nó sẽ

gởi đến Web Server có tên www.cit.ctu.edu.vn thông điệp yêu cầu sau: GET

www.cit.ctu.edu.vn HTTP/1.1\n\n

· Server sẽ gởi về nội dung sau: HTTP/1.0 200 OK Date: Mon, 24 Nov 2003

02:43:46 GMT Server: Apache/1.3.23 (Unix) (Red-Hat/Linux) mod_ssl/2.8.7

OpenSSL/0.9.6b DAV/1 .0.3 PHP/4.1.2 mod_perl/1.26 Last-Modified: Tue,

01 Jul 2003 08:08:52 GMT ETag: "17f5d-2abb-3f014194" Accept-Ranges:

bytes Content-Length: 10939 Content-Type: text/html X-Cache: HIT from

proxy.cit.ctu.edu.vn Proxy-Connection: close <!DOCTYPE HTML PUBLIC

"-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <HEAD> <LINK

href="favicon.ico" rel="SHORTCUT ICON"> ...............................

Trang 23

Hình 1.7. Thí dụ mô hình Client-Server của dịch vụ Web

1.4.3.3. Các chế độ giao tiếp

Quá trình giao tiếp giữa client và server có thể diễn ra theo hai chế độ là

nghẽn (blocked) hay không nghẽn (Non blocked).

a. Chế độ giao tiếp nghẽn:

Trong chế độ này, khi quá trình client hay server phát ra lệnh gởi dữ liệu,

(thông thường bằng lệnh send), sự thực thi của nó sẽ bị tạm dừng cho đến khi quá

trình nhận phát ra lệnh nhận số dữ liệu đó (thường là lệnh receive). Tương tự cho

trường hợp nhận dữ liệu, nếu quá trình nào đó client hay server phát ra lệnh nhận dữ

liệu, mà ở thời điểm đó chưa có dữ liệu gởi đến, sự thực thi của nó cũng tạm dừng

cho đến khi có dữ liệu gởi đến.

Trang 24

Hình 1.8 Chế độ giao tiếp nghẽn

b. Chế độ giao tiếp không nghẽn:

Trong chế độ thì của nó vẫn được tiếp tục mà không quan tâm đến việc có

quá trình nào phát ra lệnh nhận số dữ liệu đó hay không. Tượng tự cho trường hợp

nhận dữ liệu, khi quá trình phát ra lệnh nhận dữ liệu, nó sẽ nhận được số lượng dữ

liệu hiện có (bằng 0 nếu chưa có quá trình nào gởi dữ liệu đến). Sự thực thi của quá

trình vẫn được tiếp tục. Trong thực tế cần chú ý đến chế độ giao tiếp nghẽn khi lập

trình, vì nó có thể dẫn đến trường hợp chương trình bị "treo" do số lần gởi và nhận

giữ liệu không bằng nhau giữa hai bên giao tiếp. này, khi quá trình client hay server

phát ra lệnh gởi dữ liệu.

Trang 25

Hình 1.9. Chế độ giao tiếp không nghẽn

Ưu điểm: Do các dữ liệu được lưu trữ tập trung nên dễ bảo mật, sao lưu và đồng bộ

với nhau. Tài nguyên và dịch vụ được tập trung nên dễ chia sẻ và quản lý, có thể

phục vụ cho nhiều người dùng.

Khuyết điểm: Các server chuyên dụng rất đắt tiền, phải có nhà quản trị cho hệ

thống.

1.4.4. Mô hình Peer to Peer

Mạng đồng đẳng (peer-to-peer network), còn gọi là mạng ngang hàng, là một

mạng máy tính trong đó hoạt động của mạng chủ yếu dựa vào khả năng tính toán và

băng thông của các máy tham gia chứ không tập trung vào một số nhỏ các máy chủ

trung tâm như các mạng thông thường.

Mạng đồng đẳng thường được sử dụng để kết nối các máy thông qua một

lượng kết nối dạng ad hoc. Mạng đồng đẳng có nhiều ứng dụng. Ứng dụng thường

xuyên gặp nhất là chia sẻ tệp tin, tất cả các dạng như âm thanh, hình ảnh, dữ liệu,...

hoặc để truyền dữ liệu thời gian thực như điện thoại VoIP.

Một mạng đồng đẳng đúng nghĩa không có khái niệm máy chủ và máy khách,

nói cách khác, tất cả các máy tham gia đều bình đẳng và được gọi là peer, là một

Trang 26

nút mạng đóng vai trò đồng thời là máy khách và máy chủ đối với các máy khác

trong mạng.

Hình 1. Mô hình mạng P2P1.4.4.1. Phân loại mạng đồng đẳng:

Ta có thể phân loại các mạng đồng đẳng hiện nay theo tiêu chí về mức độ tập

trung của chúng như sau:

Mạng đồng đẳng thuần túy:

· Các máy trạm có vai trò vừa là máy chủ vừa là máy khách

· Không có máy chủ trung tâm quản lý mạng

· Không có máy định tuyến (bộ định tuyến) trung tâm, các máy trạm có khả

năng tự định tuyến

Mạng đồng đẳng lai:

· Có một máy chủ trung tâm dùng để lưu trữ thông tin của các máy trạm và trả

lời các truy vấn thông tin này.

· Các máy trạm có vai trò lưu trữ thông tin, tài nguyên được chia sẻ, cung cấp

các thông tin về chia sẻ tài nguyên của nó cho máy chủ.

· Sử dụng các trạm định tuyến để xác định địa chỉ IP của các máy trạm.

1.4.4.2. Ưu thế của mạng đồng đẳng

Một mục đích quan trọng của mạng đồng đằng là trong mạng tất cả các máy

tham gia đều đóng góp tài nguyên, bao gồm băng thông, lưu trữ, và khả năng tính

Trang 27

toán. Do đó khi càng có nhiều máy tham gia mạng thì khả năng tổng thể của hệ

thống mạng càng lớn. Ngược lại, trong cấu trúc máy chủ-máy khách, nếu số lượng

máy chủ là cố định, thì khi số lượng máy khách tăng lên khả năng chuyển dữ liệu

cho mỗi máy khách sẽ giảm xuống.

Tính chất phân tán của mạng đồng đẳng cũng giúp cho mạng hoạt động tốt khi

một số máy gặp sự cố. Đối với cấu trúc tập trung, chỉ cần máy chủ gặp sự cố thì cả

hệ thống sẽ ngưng trệ.

Đối với mạng Napster, thuật ngữ đồng đẳng nói lên tính chất quan trọng của

giao thức giao tiếp đồng đẳng, còn thực ra thành công của Napster phải nhờ vào sự

liên kết chặt chẽ giữa các máy tham gia với máy chủ trung tâm lưu trữ danh sách nội

dung tệp trên các máy tham gia. Nhờ vậy việc tìm kiếm trở nên nhanh và hiệu quả

hơn, tuy nhiên, đây cũng chính là điểm yếu dẫn đến các rắc rối pháp lý mà kết cục

là sự sụp đổ của Napster.

Khuyết điểm: Không cho phép quản lý tập trung nên dữ liệu phân tán, khả

năng bảo mật thấp rất dễ bị xâm nhập. Các tài nguyên không được sắp xếp nên rất

khó định vị và tìm kiếm.

1.5. Cơ chế giao tiếp liên quá trình (InterProccess Comunication)

Là sự giao tiếp, trao đổi thông tin giữa 2 hay nhiều thực thể trong hệ thống.

Trong hệ thống máy tính, hệ thống mạng máy tính: truyền thông là sự giao tiếp bên

trong 1 quá trình hay giữa các quá trình với nhau thông qua các cơ chế truyền

thông.

· Hệ thống đơn nhiệm (monotasking):

· Hệ thống đa nhiệm (multitasking):

· Giao tiếp chỉ trong phạm vi 1 chương trình.

· Dùng biến toàn cục, tham số gọi hàm, trị trả về của hàm …

· Hệ thống đa nhiệm (multitasking):

· Nhiều quá trình được thực thi song song.

· Dùng cơ chế giao tiếp liên quá trình (InterProcess Communication)

được cung cấp bởi hệ điều hành và hệ điều hành mạng.

Phân loại cơ chế giao tiếp liên quá trình:

Trang 28

Loại 1: Giao tiếp giữa các quá trình trên cùng 1 máy tính

Loại 2: Giao tiếp giữa nhiều quá

trình trên các máy tính khác nhau:

· IPC loại 1: giao

tiếp trên cùng 1

máy tính.

· Thông qua hạt

nhân (kernel) của hệ điều hành.

· Dùng vùng nhớ dùng chung hay tập tin chia sẻ:

· Một quá trình ghi

· Một quá trình đọc

· IPC loại 2: giao tiếp trên các máy tính khác nhau.

· Thông qua các hạt nhân (kernel) của nhiều hệ điều hành.

· Phải có quy tắc trao đổi thông tin (protocol) giữa các hạt nhân và giữa

các quá trình.

· Một số IPC phổ biến: Pipe, Socket, RPC.

1.6. Một số mô hình hệ thống truyền thông:

1.6.1. Hệ thống trả lời tự động IVR

1.6.1.1. Khái niệm.

IVR(Interactive Voice Response) là một công nghệ mới trong ngành điện

thoại, nơi mà người gọi sẽ sử dụng một điện thoại thông thường hay một công nghệ

điện thoại nào đó để có thể lấy thông tin từ database của một tổ chức hoặc để nhập

dữ liệu vào trong đó. Các tổ chức kinh doanh ngày một sử dụng IVR nhiều hơn

nhằm giảm chi phí cho các hoạt động bán hàng, giao dịch, hỗ trợ, khuyễn mãi…

thông qua điện thoại. Người dùng có thể gửi tin nhắn theo một cú pháp nhất định tới

hệ thống và hệ thống sẽ phân tích cú pháp tin nhắn rồi truy vấn CSDL sau đó sẽ gửi

lại thông tin cho người sử dụng. Hoặc người sử dụng có thể gọi điện đến đệ thống,

Trang 29

sử dụng bàn phím điện thoại để “nói chuyện” với hệ thống IVR, và IVR “nghe” các

phím bấm đó rồi đọc lại cho người gọi điện các thông tin được yêu cầu.

IVR sử dụng các giọng nói ghi sẵn để phát ra danh sách các thông tin có khả

năng cung cấp và các thông tin lấy từ cơ sở dữ liệu của nhà cung cấp dịch vụ (có thể

là số hoặc văn bản) sau khi tổng hợp thành tiếng nói.

Ngoài việc trả lời các cuộc gọi đến, IVR còn có khả năng tự động gọi đến các

thuê bao cố định hay di động để cung cấp hoặc thu thập các thông tin như thông

báo, lời nhắn, cuộc hẹn, tiền cước, số dư tài khoản, giao dịch phát sinh, thông tin

khuyến mãi, trắc nghiệm, điều tra…

Lấy một ví dụ, một vài tổ chức sử dụng hệ thống IVR cho phép khách hàng

lấy thông tin về tài khoản đựợc cập nhật ngay thời điểm hiện tại(24h trong ngày)

mà không phải giao dịch trực tiếp với một nhân viên chăm sóc khách hàng nào. Hệ

thống thông tin tự động sẽ bao gồm những chức năng như: là nơi những thông tin

về tài khoản khách hàng có thể được đưa ra một cách tự động theo từng lĩnh vực

phù hợp với yêu cầu của khách hàng. Người sử dụng chỉ việc chọn loại thông tin

cần biết và nhận thông tin đó bằng giọng nói được ghi âm sẵn trong hệ thống.

Hình 1.10 Mô hình Hệ thống IVR

Công nghệ IVR cũng có thể được sử dụng vào mục đích thu thập thông tin, ví

dụ như những cuộc khảo sát qua điện thoại. Người sử dụng sẽ được hướng dẫn để

trả lời những câu hỏi bằng cách nhấn vào phím số trên điện thoại hoặc trả lời

Trang 30

bằng miệng đối với trường hợp có phần mềm thu lại giọng nói được tích hợp trong

hệ thống IVR.

Một vài tổ chức tạo ra một bài kiểm tra để xác định sự hài lòng của khách hàng

bằng cách mời họ tham gia vào một cuộc điều tra nhỏ sau khi sử dụng bất kỳ một

dịch vụ nào đó. Nếu như khách hàng nhận lời thì cuộc gọi sẽ được chuyển tới bộ

phận khảo sát có sử dụng chức năng IVR và tổ chức đó sẽ thu thập những đánh giá

của khách hàng về chất lượng dịch vụ.

1.6.1.2. Các dịch vụ điển hình của IVR.

Bưu điện: Hộp thư thông tin, Hộp thư thoại, Quà tặng âm nhạc, Báo thức,

Nhắc nợ, Báo máy hỏng tự động, Bình chọn, Dự đoán…

1900xxxx: Các dịch vụ giải trí truyền hình, trò chơi truyền hình (vd: Hugo),

bình chọn ca sĩ, dự đoán kết quả bóng đá qua điện thoại và tin nhắn SMS.

Ngân hàng/Chứng khoán: Phonebanking: Trạng thái tài khoản, thanh toán,

chuyển khoản, tiện ích, kích hoạt tài khoản, thẻ tín dụng, tỷ giá, lãi suất.

Vận tải/Hành khách: Tra cứu chuyến/giá cả/số ghế, đặt chỗ, Hỏi giờ xuất

phát/đến nơi

Quan hệ khách hàng: Nghiên cứu thị trường, điều tra nhu cầu tiêu dùng.

Thu nợ: Trạng thái tài khoản (số dư, tiền nợ), thông báo cước, thanh toán.

Chăm sóc sức khỏe: Hẹn khám sức khỏe, hướng dẫn của bác sĩ, kết quả khám

bệnh, thông tin dịch vụ.

Giáo dục-Nghề nghiệp: Đăng ký tuyển dụng, tìm việc, đăng ký nhập học, thời

khóa biểu, lịch thi, điểm thi, điểm danh, thông báo, thông tin trợ giúp.

Bảo hiểm: Thông tin chính sách, danh mục đại lý, yêu cầu bảo hiểm, thanh

toán phí.

Bán hàng: Đặt hàng, thanh toán bằng thẻ tín dụng, tra cứu thông tin hàng, tra

cứu trạng thái đặt hàng và chuyển hàng.

1.6.1.3. Các ưu điểm của hệ thống IVR.

· Giúp tự động hóa cung cấp thông tin, hỏi đáp

· Mở ra kênh giao tiếp khách hàng mới một cách hữu hiệu.

· Đem lại nhiều lợi ích và doanh thu cho đơn vị sử dụng.

Trang 31

· Đem lại các giá trị mới, sự thuận tiện và tiện ích cho khách hàng, nâng

cao hình ảnh thương hiệu.

· Đa dạng hóa các dịch vụ cung cấp thông tin và chăm sóc khách hàng

Tất các các ưu điểm trên sẽ mang lại lợi nhuận cho nhà cung cấp và khả năng

đáp ứng cho khách hàng lớn.

1.6.1.4. CallXML-CCXML

CallXML là ngôn ngữ XML dùng để định nghĩa các thao tác và nội

dung giao tiếp với khách hàng thông qua cuộc điện thoại cho ứng dụng IVR. Phát

triển bởi Lucent, AT&T, IBM, và Motorola. Phiên bản 1. 0 ra đời vào 3/2000.

Phiên bản thử nghiệm 2. 0 ra đời 10/2001. Phiên bản 2. 0 chính thức vào 01/2003.

CallXML - CCXML là viết tắt của Call Control Markup Language. Tính năng

chính bao gồm:

· Cho phép thiết lập cuộc gọi ra

· Cho phép đàm thoại tay ba

· Dẫn hướng cuộc gọi vào

· Nắm bắt được các sự kiện xảy ra bên ngoài khi cuộc gọi đang diễn ra

· Điện thoại hội nghị, cho phép thêm hoặc bớt thành viên

· Điều khiển được chất lượng ânh thanh, âm lượng, phát nhanh/chậm

· Chuyển hướng từy ý đến bất kỳ thông tin nào

· Giao tiếp với các phần mềm ứng dụng khác thông qua sự kiện

· Chuyển lời nhắn riêng cho các cuộc gọi khác

· Thiết lập cuộc gọi giám sát hay quản lý

1.6.2. Hộp thư thoại (voicemail)

Voicemail (còn được gọi là voice-mail, voice message, or voice bank) là một

hệ thống máy tính cho phép người sử dụng và thuê bao trao đổi thông điệp thoại cá

nhân, lựa chọn và cung cấp thông tin bằng giọng nói, và để xử lý các giao dịch liên

quan đến cá nhân, tổ chức, sản phẩm và dịch vụ bằng cách sử dụng một điện thoại

bình thường. Voice-mail cũng được sử dụng rộng rãi hơn để biểu thị bất kỳ hệ thống

truyền đạt một thông điệp viễn thông bằng giọng nói được lưu trữ trong hệ thống,

Trang 32

bao gồm cả việc sử dụng một máy trả lời (answer machine). Hầu hết các dịch vụ

cell phone cung cấp tính năng voice-mail cơ bản.

Hệ thống voice-mail được thiết kế để truyền đạt một thông điệp được ghi sẵn

dạng audio đến người nhận. Để làm như vậy người ta sử dụng một giao diện người

dùng cho phép lựa chọn, phát, và quản lý thông điệp thoại, một phương thức phân

phối hoặc phát hoặc gửi thông điệp đó và khả năng gửi thông điệp đó đến hàng đợi

của người sử dụng. Hầu hết các hệ thống sử dụng các mạng điện thoại, hoặc di động

hoặc đường điện thoại có dây đều có tất cả các chức năng này. Một số hệ thống có

thể sử dụng nhiều phương pháp viễn thông, cho phép người nhận và người gọi để

truy xuất hoặc để lại tin nhắn thông qua nhiều phương thức như máy tính, PDA,

điện thoại di động hoặc điện thoại thông minh.

Hệ thống hộp thư thoại đơn giản có chức năng như một máy trả lời từ xa bằng

cách sử dụng một touch-tones như giao diện người dùng. Nhiều hệ thống phức tạp

có thể sử dụng các thiết bị đầu vào khác chẳng hạn như voice hoặc giao diện máy

tính. Hệ thống thư thoại đơn giản có thể play các tin nhắn âm thanh thông qua điện

thoại, trong khi hệ thống cao cấp hơn có thể có phương pháp phân phối khác như

cung cấp thư điện tử hoặc tin nhắn văn bản, truyền thông tin và chuyển tiếp

(forwarding) và các mailbox.

Hầu như tất cả các hệ thống hộp thư thoại hiện đại sử dụng lưu trữ kỹ thuật số

và thường được lưu trữ trong máy tính. Phương thức cũng khác nhau dựa trên hệ

thống voice mail. Hệ thống đơn giản không thể cung cấp tất cả các tính năng thay vì

yêu cầu người nhận phải kiểm tra với hệ thống, trong khi những người khác có thể

đợi tin nhắn.

Interactive Voice Response (IVR) hệ thống có thể sử dụng thông tin kỹ thuật

số được lưu trữ trong một cơ sở dữ liệu doanh nghiệp để lựa từ và cụm từ được lưu

trữ trong từ vựng voice-mail để tạo thành câu được gửi đến người gọi.

1.6.3. Dịch vụ tin nhắn SMS

Dịch vụ tin nhắn ngắn (SMS - Short Message Services) là một giao thức viễn

thông cho phép gửi các thông điệp dạng text ngắn (không quá 160 chữ cái). Giao

Trang 33

thức này có trên hầu hết các điện thoại di động và một số PDA với khả năng truyền

thông không dây.

SMS Gateway là cổng kết nối tới các nhà khai thác mạng viễn thông di động (

Vinaphone, MobiFone, Sfone, Viettel, EVN, Beeline ..) cho phép các đối tác tổ

chức những chương trình sử dụng tin nhắn SMS, MMS làm phương tiện tương tác

với khách hàng của mình.

Trang 34

Hình 1.9. Mô hình dịch vụ cung cấp tin nhắn SMS

Cơ chế hoạt động hoạt động:

· CP : đơn vị cung cấp nội dung ( Content Provider )

· Chuẩn bị nội dung

· Tạo Keyword : khách hàng nhắn tin SMS đến để lấy thông tin

· Quảng cáo, marketing qua các hình thức khác nhau để khách hàng biết

các dịch vụ SMS của chính mình

· Khách hàng

· Biết được hệ thống SMS của CP qua các nguồn khác nhau

· Nhắn tin SMS để nhận các nội dung được CP cung cấp.

Nguyên tắc các CP nhận tiền:

· Việc kinh doanh sẽ phụ thuộc vào số lượng khách hàng nhắn tin SMS vào

· Các Telco sẽ thu phí trực tiếp với tiền từ tài khoản của các điện thoại di

động.

· Telco thanh toán cho Fibo sau khi đã hoàn tất các đối soát cước.

· Cước sẽ được Fibo thanh toán cho CP theo đúng hợp đồng đã ký giữa 02

bên

· Thông thường tổng doanh thu đến CP được tính như sau

· Tổng Doanh Thu CP= Chi phi VND/1SMS – Phí Telco – Phí Fibo

Một số ứng dụng thích hợp cho SMS Gateway:

· Khuyến mãi, chào hàng

· Thi/nhắn tin để chiến thắng

· Tổ chức cuộc thi, trò chơi trên SMS

· Đấu giá

· Bình chọn

· Thi trí tuệ, hỏi đáp nhanh

· Trò chơi tương tác

· ……………

· Cung cấp dữ liệu nội dung số

· tin nhắn thoại

Trang 35

· tin nhắn hình

· tải nhạc chuông, nhạc chuông chờ, nhạc chuông hot

· sms tình yêu

· mobile content : dữ liệu, games, tài liệu

· Tổ chức, quản lý các sự kiện

· Tương tác với màn hình lớn

· Đặt mua hàng đặc biệt, số lượng hạn chế

1.6.4. Voice over IP

1.6.4.1. Giới thiệu về VoIP:

VoIP là từ viết tắt của Voice Over Internet Protocol. Đúng như tên gọi của

chúng, nghi thức truyền âm thanh này sử dụng phương pháp truyền tín hiệu âm

thanh thông qua truyền các gói tin thông qua mạng IP. Bằng cách này, VoIP có thể

sử dụng tốc độ của phần cứng để hoàn thành mục đích và có thể hữu dụng trên môi

trường PC.

VoIP có khả năng kết hợp thoại và dữ liệu trong quá trình xử lý truyền, phân

phối thông, cuộc gọi điện thoại, hội nghị truyền hình, các trò chơi tương tác trực

tuyến cũng như phân phối các ứng dụng truyền thanh, truyền hình và phát quảng

bá.

Đây là công nghệ viễn thông hấp dẫn và được chú ý nhiều nhất hiện nay. Việc

sử dụng VoIP làm cho quá trình phân phối thông tin và dịch vụ toàn cầu hiệu quả

hơn và kinh tế hơn so với sử dụng mạng chuyển mạch thoại công cộng truyền

thống (PSTN), trong khi đó vẫn cho phép sử dụng các ứng dụng và dữ liệu trước

đây. VoIP có thể thực hiện tất cả các chức năng tương tự với mạng truyền thống

với chất lượng dịch vụ tốt.

1.6.4.2. Ưu điểm của VoIP so với PSTN:

a. Tiết kiệm băng thông:

Mạng VoIP hiệu quả hơn mạng PSTN trên cơ sở các kênh chuyên dùng được

thiết lập giữa các điểm cuối. Ðối với cuộc gọi thông thường có đến 40% thời gian

bị lãng phí bởi những khoảng lặng (không nói chuyện). Trong mạng VoIP, các gói

chỉ được gởi qua mạng khi có tín hiệu cần truyền đi. Ðiều này cho phép mạng có

Trang 36

thể điều khiển được một lưu lượng nhiều hơn qua độ rộng băng thông sẵn có.

b. Đơn giản hóa:

VoIP là môt mô hình tổng hợp, chấp nhận mọi dạng thông tin cho phép thực

hiện việc chuẩn hoá và giảm bớt một phần trang thiết bị dùng riêng cho từng loại

hình. Tích hợp các ứng dụng về thoại và dữ liệu.

c. Khả năng tích hợp:

Khả năng này được minh họa một cách rõ nhất bằng việc hỗ trợ phối hợp giữa

mạng không dây và mạng có dây, khả năng hợp nhất các ứng dụng riêng lẽ trong

truyền thống qua các giao thức gắn kết.

Sự tích hợp qua mạng IP đưa ra các giải pháp truy cập hợp nhất các dịch vụ

trong mạng diện rộng WAN bao gồm thoại, dữ liệu, Internet, hình ảnh qua một hệ

thống các đường truy cập tốc độ cao dùng chung.

d. Uyển chuyển trong quản lý:

Được thể hiện qua khả năng mở rộng của địa chỉ IP, có thể mở rộng hay thu

hẹp phạm vi của mạng một cách dễ dàng mà không gây nên sự biến đổi lớn nào về

phần cứng và phần mềm..

Việc thêm hay bớt người sử dụng điện thoại, sắp xếp lại các số trên mạng IP

đều dễ dàng hơn so với hệ thống chuyển mạch thoại truyền thống. Việc định dạng

và chuyển nhượng địa chỉ IP có thể được thực hiện bằng cách sử dụng giao thức

DHCP, áp dụng cho điện thoại IP qua LAN khiến việc lập và quản lý địa chỉ gần

như tự động.

Đối với việc kết nối với tổng dài nội bộ (PBX) qua mạng IP được đưa ra bởi

PSINet’s Voice iPEnterprise, phân phối lưu lượng thoại nội bộ qua kết nối tượng tự

như dữ liệu của Internet, cho phép các nhà kinh doanh truyền các dịch vụ thoại tới

văn phòng của họ.

e. Quản lý tốt:

Giao thức quản lý SNMP có thể áp dụng vào cho dữ liệu và thoại dùng trong

VoIP để có thể loại bỏ sai sót và củng cố hệ thống Được phát triển trên mạng IP,

VoIP sử dụng các giải pháp bảo mật cho Internet gồm mã hoá, tạo đường hầm, xác

nhận sự xâm nhập tự động, quét virus được thực hiện bởi các máy chủ, firewall,

Trang 37

các bộ định tuyến đã giải quyết được các vấn đề về gian lận cước phí, toàn vẹn dữ

liệu.

f. Giá thành thấp:

Việc giảm chi phí tài nguyên mạng, chia sẽ trang thiết bị và chi phí vận hành

cho cả tín hiệu thoại và dữ liệu có thể nâng cao hiệu quả sự dụng mạng vì phần

băng thông dư trên mạng này có thể tận dụng trên mạng khác, dẫn đến tỷ lệ cước

phí khi sử dụng thoại và Fax kết hợp trong truy cập Internet có thể tiết kiệm đáng

kể chi phí cho người dùng so với dùng mạng PSTN.

1.6.4.2. Các hình thức truyền thoại trên mạng IP

a. PC-PC :

Mỗi PC trang bị thêm các thiết bị truyền thông và được kết nối trực tiếp vào

mạng Internet thông qua giao diện NIC với mạng LAN hoặc thông qua Modem /

cable modem khi kết nối qua ISP (Internet Sevice Provider).

b. PC – Phone :

Người dùng PC hình thành cuộc gọi với người dùng mạng thoại PSTN thông

thường. Cấu trúc này là đường dẫn tới việc kết hợp giữa mạng IP và PSTN.

c. Phone - Internet - Phone :

Là mô hình mở rộng của PC – Phone, sử dụng Internet làm cơ sở để tính cước

phí điện thoại cho người sử dụng mạng PSTN. Mô hình này sử dụng một mã số đặc

biệt là giá trị cổng kết nối giữa PSTN và mạng Internet rồi mới nhấn số điện thoại

cần gặp. Mọi quá trình lấy mẫu và mã hoá đều diễn ra ở gateway.

1.6.4.3. Nguyên tắc và mô hình hoạt động của VoIP

a. Quá trình thiết lập một kết nối VoIP

- Bộ phận ADC chuyển đổi âm thanh dạng tín hiệu tương tự sang tín hiệu số,

được biểu diễn bằng các chuỗi bit.

- Các chuỗi bit này được nén với một định dạng để truyền bằng các nghi

thức nén dữ liệu phù hợp tuỳ chọn.

- Đóng gói âm thanh vào gói dữ liệu và truyền đi bằng nghi thức

RTP(real-time transport protocol), thông thường sử dụng RTP over UDP.

- Dùng nghi thức báo hiệu ITU-T H323 để gọi các user.

Trang 38

- Bên RX sẽ mở gói tin, giải nén dữ liệu, chuyển dữ liệu từ tín hiệu số sang

tín hiệu âm thanh dạng tương tự và gửi tới card âm thanh (hay phone).

b. Mô hình hoạt động của VoIP

1.6.4.4. Các nghi thức được sử dụng trong hệ thống VoIP

a. Giao thức UDP (User Datagram Protocol)

UDP thực hiện truyền dữ liệu với số header hạn chế tối đa vì giao thức này

không đòi hỏi kiểm tra qua lại giữa bên nhận và bên phát. Các gói tìm đường độc

lập để đến nơi nhận, do đó không đảm bảo dữ liệu được nhận đầy đủ và đúng thứ

tự. Tuy nhiên, thời gian truyền dữ liệu ngắn với độ hiệu quả sử dụng các gói cao

nên UDP được sử dụng là giao thức chính trong VoIP.

b. Giao thức RTP (Realtime Protocol):

Giao thức này cung cấp các dịch vụ về dữ liệu mang tính thời gian thực như

video và audio tương tác. Các ứng dụng này chạy dựa trên nền UDP để tận dụng

được khả năng multiplexing và checksum. Cả hai giao thức này góp phần tạo nên

các tính năng của nghi thức truyền dữ liệu. RTP có thể được dùng hiệu quả hơn

trong các hệ thống mạng hay nghi thức thích hợp. RTP cũng hỗ trợ truyền dữ liệu

đến nhiều địa chỉ khác nhau bằng cách dùng cơ chế multicast nếu được sự hỗ trợ

của hệ thống mạng. Chúng ta sẽ tìm hiểu rõ hơn về nghi thức này trong phần tìm

Trang 39

hiểu về các nghi thức mạng truyền dữ liệu theo thời gian thực.

c. Giao thức RTCP ( RTP Control Protocol ):

Giao thức điều khiển RTP truyền các gói điều khiển theo chu kỳ cho mọi

thành viên trong phiên làm việc, sử dụng cùng một cơ chế phân phối như đối với

các gói dữ liệu. RTCP thực hiện bốn chức năng sau: Cung cấp các phản hồi về chất

lượng của quá trình phân phối dữ liệu, giữ vết các thành phần tham gia, kiểm soát

tốc độ để có thể phục vụ cho một số lượng lớn các thành phần tham gia, kiểm soát

phiên làm việc.

d. Giao thức RSVP:

Hỗ trợ cho giao thức RTP, giao thức RSVP có thể giải quyết tạm thời các lỗi

có thể xảy ra trên đường truyền để đảm bảo các tham số chất lượng. Giao thức RTP

chỉ kiểm tra sự truyền thông điểm - điểm, không quản lý các tham số liên kết trên

mạng trong khi RSVP không những tác động ở máy phát và máy thu mà còn tác

động trên các router trên mạng.

RSVP thiết lập và duy trì kết nối duy nhất cho một luồng dữ liệu, xác lập một

hệ thống quản lý các nguồn tài nguyên của các nút mạng khác nhau.

RSVP hoạch định một mô hình tối ưu để liên kết các dữ liệu đa điểm ( từ một

nguồn đến nhiều điểm đích). RSVP đóng vai trò quản lý một cách độc lập các máy

đích để tự thích nghi các tham số chất lượng giữa khả năng cung cấp và yêu cầu

đáp ứng.

Ðể đảm bảo đường truyền thông suốt, các hệ thống đầu cuối phải hoạt động ở

chế độ kết nối. Máy thu phải thường xuyên gởi các thông điệp RSVP đến các

router để đảm bảo thông suốt đường truyền.

e. SGCP:

Giao thức này cho phép các thành phần điều khiển cuộc gọi có thể điều khiển

kết nối giữa các trung kế, các Endpoint và cácVoIP gateway. Các thành phần điều

khiển gọi là Call Agent. SGCP được dùng để thiết lập duy trì và giải phóng cuộc

gọi qua mạng IP. Call Agent thực hiện chức năng báo hiệu cuộc gọi và Gateway

cung cấp chức năng truyền tín hiệu âm thanh. SGCP yêu cầu các Gateway thực

hiện chức năng thiết lập, điều chỉnh, giải phóng kết nối và báo hiệu về Call Agent

Trang 40

các sự kiện xảy ra tại gateway. SGVP có 5 lệnh chính như sau:

- NotificationRequest: yêu cầu Gateway phát hiện các tín hiệu nhấc máy và

tín hiệu quay số DTMF.

- Notify: Gateway sử dụng lệnh này để báo ngược về Call Agent các tín hiệu

trên.

- CreateConnection: Call Agent yêu cầu tạo kết nối giữa cá đầu cuối tham

gia liên lạc trong gateway.

- ModifyConnection: Call Agent dùng lệnh này để thay đổi các thông

số về kết nối đã thiết lập. Lệnh này để thay đổi các thông số về kết nối đã thiết lập.

Lệnh này cũng có thể dùng các gói RTP thay đổi lộ trình từ Gateway này sang

Gateway khác.

- Deleteconnection: Call Agent và Gateway dùng lệnh này để giải phóng kết

nối.

f. MGCP:

MGCP xác định cách thức truyền thông giữa các đại lý(call agent) và các

cổng điện thoại (telephony gateway). Call agent điều khiển cuộc gọi, quản lý các

telephony gateway được dùng để chuyển đổi giao thức. MGCP có bốn lệnh chính

như sau:

- EndPointConfiguration: Call Agent dùng lệnh này để yêu cầu Gateway

xác định kiểu mã hoá ở phía đường dây kết nối tới EndPoint.

- AudiEndpoint và AudiConnection: Call Agent kiểm tra trạng thái và kết

nối ở một Endpoint.

- RestarIn_Progress: Gateway báo hiệu cho Call Agent khi nào các

Endpoint ra khỏi dịch vụ hoặc quay lại sử dụng dịch vụ.

1.6.4.5. Các vấn đề liên quan đến chất lượng dịch vụ

Chất lượng của các dịch vụ truyền thông đa phương tiện được xem là vấn đề

quan quyết định sự phát triển của dịch vụ đó. Mọi dịch vụ truyền thông đa phương

tiện phát triển trên mạng VoIP đều phải khắc phục chất lượng về âm thanh sau khi

nén và điều này là một trong những lý do quan trọng nhất khiến VoIP không cạnh

tranh được với mạng điện thoại truyền thống PSTN. Có 3 yếu tố chính gây ảnh

Trang 41

hưởng trực tiếp đến chất lượng tín hiệu thoại trong VoIP là : mất gói, trễ gói và

jitter.

a. Mất gói và các giải pháp khắc phục tình trạng này:

· Là hiện tượng chung trong môi trường chuyển mạch gói.

· Các gói được truyền giữa các đầu cuối thông qua các router trung gian.

Khi các router này quá tải, nghẽn mạch sẽ dẫn đến mất gói.

Các giải pháp khắc phục:

· Nâng cấp mạng

· Lấp gói mất bằng khoảng lặng

· Thay thế các gói mất bằng cách chèn nhiễu trắng.

· Phát lại gói cuối nhận được với âm lượng nhỏ hơn.

· Thêm gói dựa vào đặc tính sóng âm của các gói lân cận.

· Chèn khung thoại vào các gói khác nhau

b.Trễ gói

· Giới hạn của delay là 150ms, với đường truyền xa thì delay chấp nhận

được là từ 150->400ms.

· Trễ gói làm tiếng nói không thực, chồng lấp tiếng nói, tạo tiếng vọng,…

· Nguyên nhân: do độ trễ của quá trình mã hoá, giải mã tiếng nói gây ra,

thời gian truyền, hay do xếp hàng trong các buffer tại các nút chuyển mạch

và nút truyền số liệu, …

Có hai giải pháp:

· Nén Header: mỗi gói dữ liệu đều kèm theo các header để tìm đường

chuyển các gói đến đúng nơi nhận.

· Phân đoạn: các gói thoại sử dụng các giao thức thời gian thực như RTP,

RTCP, RSVP sẽ được ưu tiên hơn trong truyền thông.

c. Network Jitter

· jitter là khoảng thời gian đến nơi nhận khác nhau của các gói thoại, là yếu

tố ảnh hưởng nghiêm trọng đến chất lượng thoại trong VoIP.

· Để giải quyết vấn đề này, phía thu phải có một bộ đệm jitter để sắp xếp

các gói nhận theo đúng thứ tự phát. Thời gian lưu trữ làm tăng thêm thời

Trang 42

gian delay.

· Các gateway cần có khả năng thay đổi kích thước bộ đệm jitter để thích

nghi với thời gian trễ trong mạng.

· Kích thước chung của buffer là 50-100ms.

· Ngoài ra nghẽn mạch trên mạng cũng ảnh hưởng rất lớn đến chất lượng

thoại.

Trang 43

CHƯƠNG 2 : LẬP TRÌNH JAVA

2.1. Lập trình hướng đối tượng và lập trình có cấu trúc

Phương pháp lập trình truyền thống chúng ta vẫn áp dụng đó là lập trình có cấu

trúc. Phương pháp lập trình này thưc hiện theo cách tiếp cận hướng chức năng dựa

chủ yếu vào việc phản tách các chức năng chính của bài toán thành những chức

năng đơn giản hơn và thực hiện làm mịn dần từ trên xuống (top-down). Theo cách

tiếp cận hướng chức năng, chương trình được xem như là một tập các hàm chức

năng, trong đó đứ liệu và các hàm là tách rời nhau. Đổi với những hệ thông lớn,

phức hợp, độ phức tạp của chương trình tăng lên, sự phụ thuộc của nó vào các kiểu

dữ liệu mà nó xứ lý cũng tăng theo. Các kiểu đã liệu được xử lý trong nhiều chức

năng bên trong chương trình có cấu trúc, và khi có sự thay đổi về kiểu dữ liệu thì

cũng phải thực hiện thay đổi ở mọi nơi mà đứ liệu đó được sử dụng. Một nhược

điểm nữa của 1ập trình hướng chức nàng là khi có nhiều người tham gia xây dụng

chương trình, mỗi người được giao viết một số chức năng (hàm) riêng biệt nhưng lại

phải sử dụng chung dữ liệu. Khi có nhu cầu cần thay đổi đữ liệu sẽ ảnh hướng rất

lớn đến công việc của nhiều người, v.v.

Lập trình hướng đối tượng đưa trên nền tảng là các đối tượng. Đối tượng (thực

thể) được xây dựng trên cơ sở gắn dữ liệu với các phép toán sẽ thể hiện được đúng

cách mà chúng mà suy nghi, bao quát về chúng trong thể giới thực.

Chẳng hạn, ô tô có bành xe, di chuyển được và hướng của nó thay đổi được

bằng cách thay đổi tay lái. Tượng tư, cây là loại thưc vật có thân gỗ và lá. Cây

không phải là ô tô và những gì thực hiện được với ô tô sẽ không làm được với cây.

Lập trình hướng đối tượng cho phép kết hợp những tri thức bao quát về các

quá trình thực tế với những khái niệm trừu tượng được sử dụng trong máy tính.

Chương trình hay hệ thống hướng đối tượng được xem như là tập các lớp đối tượng

tương tác với nhau để thưc hiện các yêu cầu của bài toán đặt ra.

Như vậy, hiện nay có hai cách tiếp cận cơ bản để phát triển các hệ thống

phần mềm: đó là cách tiếp cận hướng chức năng (Function-Oriented) và hướng đối

Trang 44

tượng (Object-Oriented). Cả hai cách tiếp cận này đều áp dụng một nguyện lý

chung để mô hình hóa hệ thống là thực hiện “chia để trị”, phân chia bài toán thành

những đơn vị tương đối đơn giản mà có thể dễ dàng quẩn lý được chúng một cách

có hiệu quả.

2.1.1. Lập trình hướng chức năng

Những ngôn ngữ lập trình bậc cao truyền thông như COBOL, FORTRAN,

PASCAL, C, ..., được gọi chung là ngôn ngữ lập trình hướng chức hăng. Theo cách

tiếp cận hướng chức năng thì một hệ thống phần mềm được xem như là dãy các

công việc (chức năng) cần thực hiện như nhập dữ liệu, tính toán, xử lý, lập báo cáo

và in ẩn kết quả v.v... Mỗi công việc đó sẽ được thực hiện bởi một số hàm nhất

định. Như vậy, trọng tâm của cách tiếp cận này là các hàm chức năng, cấu trúc của

chương trình được xây dựng theo cách tiếp cận hướng chức năng có dạng như hình

dưới đây:

Hình 2.1. Cấu trúc chương trình hướng chức năng

Lập trình hướng chức năng (LTHCN) sử dụng kỹ thuật phân rã các chức năng

(hàm) theo các tiếp cận top-down để tạo ra cấu trúc phân cấp - Chương trình được

xây dựng theo cách tiếp cận hướng chức năng thực chất là tập các chương trình con

(có thể xem như là các hàm) mà theo đó máy tính cẩn thực hiện để hcàn thành

những nhiệm vụ đặt ra của hệ thống.

Trang 45

Khi đặt trọng tâm vào các hàm thì dữ liệu, những cái mà các hàm sử dụng để

thực hiện công việc của mình lại trở thành thứ yếu. Cái gì sẽ xảy ra đối với dữ liệu

và gắn dữ liệu với các hàm như thế nào? cùng nhiều vấn đề khác cẩn phải gìải quyết

khi muốn xây dựng các phương pháp phù hợp để phát triển những hệ thống phần

mếm giải quyết những yêu cầu đặt ra của thực tế. Hơn nữa, hệ thống luôn là một thể

thống nhất, (Vì vậy các hàm trong một chương trình phải có liên hệ, trao đổi được

với nhau. Như chúng ta đã biết, các hàm (các bộ phận chức năng) chỉ có thể trao đổi

được với nhau thông qua các tham số: nghĩa là phải sử dụng biến chung (global).

Mỗi hàm có thể có vùng dữ liệu riêng còn gọi là dữ liệu cục bộ (local). Mối quan hệ

giữa dữ liệu và hàm trong chương trình hướng chức năng được mô tả trong hình

sau:

Hình 2.2. Mối quan hệ giữa dữ liệu và hàm trong LTHCN

Nhiều hàm có thể truy nhập, sử dụng dữ liệu chung, làm thay đổi giá trị của

chúng và vì vậy rất khó kiểm soát. Khi muốn thay đổi, bổ sung cấu trúc đã liệu dùng

chung cho một số hàm thì người lập trình phải thay đổi hầu như tất cả các hàm liên

quan đến dữ liệu đó. Nhất là đối với những chương trình, dự án tin học lớn, phức

tạp đòi hỏi nhiều người, nhiều nhóm tham gia thì những thay đổi của những biển dữ

liệu chung sẽ ảnh hưởng tới tất cả những mối có liên quan tới chúng.

Một đặc tính nữa của cách tiếp cận hướng chức năng dễ nhận thấy là tính mở

(open) của hệ thống kém. Thứ nhất, vì dựa chính vào chức năng mà trong thực tế

nhiệm vụ của hệ thống lại hay thay đổi nên khi đó muốn cho hệ thống đáp ứng các

yêu cầu thì phải thay đổi lại cấu trúc của hệ thống, nghĩa là phải thiết kế, lập trình

Trang 46

lại hệ thống. Thứ hai, việc sử dụng các biến dữ liệu chung trong chương trình làm

cho các nhóm chức năng phụ thuộc vào nhau về cấu trúc đã liệu nên cũng hạn chế

tính mở của hệ thống. Trong thực tế, cơ cấu tổ chức của mọi tổ chức lại thường ít

thay đổi hơn là chức năng, nhiệm vụ phải thực hiện.

Mặt khác, cách tiếp cận hướng chức năng lại tách dữ liệu khối chức năng xử lý

nên vấn đề che giấu, bảo vệ thông tin trong hệ thống là kém, nghĩa là vấn đề an

toàn, an ninh dữ liệu là rất phức tạp.

Ngoài ra cách tiếp cận huớng chức năng cũng không hỗ trợ việc sử dụng lại và

kế thừa nên chất lượng và giá thành của phần mềm ít được cải thiện.

2.1.2. Lập trình hướng đối tượng

Lập trình hướng đối tượng (LTHĐT) đặt trọng tâm vào các đối tượng, yếu tố

quan trọng trong quá trình phát triển chương trình và nó không cho phép dữ liệu

tách biệt, chuyển động tư do trong hệ thôdng. Dữ liệu được gắn chặt với các hàm

thành phần và chúng được tổ chức, quản lý truy nhập theo nhiều mức khác nhau.

LTHĐT cho phép phân tích bài toán thành tập các thực thể được gọi là các lớp

đối tượng, sau đó xây dựng các dữ liệu thành phần cũng với các hàm thành phần

thao tác trên các dữ liệu đó và trao đổi với những đối tượng khác để thưc hiện

những nhiệm vụ được giao).

Một chương trình, một hệ thống được xem như là một tập các lớp đối tượng và

các đối tượng đó trao đổi với nhau thông qua việc gửi và nhận các thông điệp

(message). Do vậy, một chương trình hướng đối tượng thực sự có thể hoàn toàn

không cần sử dụng biến chung.

Lập trình hướng đối tượng dựa chủ yếu vào các đối tượng, nên khi có nhu cầu

thay đổi thì chỉ cần thay đổi ở một số 1ớp có liên quan, hoặc có thể bổ sung một số

lớp mới trên cơ sở kế thừa và sữ dụng lại nhiều nhất có thể. Mặt khác, như trên đã

phân tích, một chương trình hướng đối tượng có thể không sử dụng hoặc hạn chế sử

dụng các biến chung, do vậy đễ dàng tạo ra được những hệ thống có tính mở cao

hơn.

Cơ chế bao học, che giấu thông tin của phương pháp hướng đối tượng giúp tạo

ra được những hệ thống an toàn, an ninh cao hơn cách tiếp cận hướng chức năng.

Trang 47

Hơn nữa, phương pháp hướng đối tượng còn hỗ trợ rất mạnh nguyên lý sử

dụng lại nhiều nhất có thế và tạo ra mọi khả năng để kế thừa những lớp đã được

thiết kế, lập trình tốt để nhanh chóng tạo ra được những phần mềm có chấtt lượng,

giá thành rẻ hơn và đáp ứng các yêu cầu của người sử dụng.

2.2. Lịch sử phát triển của ngôn ngữ java

Năm 1990, Sun MicroSystems thực hiện dự án Green nhằm phát triển phần

mềm trong các thiết bị dân dụng. James Gosling, chuyên gia lập trình đã tạo ra một

ngôn ngữ lập trình mới có tên là Oak. Ngôn ngữ này có cú pháp gần giống như C++

nhưng bỏ qua các tính năng nguy hiểm của C++ như truy cập trực tiếp tài nguyên hệ

thống, con trỏ, định nghĩa chồng các tác tử… Khi ngôn ngữ Oak trưởng thành,

WWW cũng đang vào thời kỳ phát triển mạnh mẽ, Sun cho rằng đây là một ngôn

ngữ thích hợp cho Internet. Năm 1995, Oak đổi tên thành Java. Đến 1996 Java đã

được xem như một chuẩn công nghiệp cho Internet.

Khả năng của ngôn ngữ java:

· Là một ngôn ngữ bậc cao như C, C++, Perl, SmallTalk,.. cho nên có thể được

dùng để tạo ra các ứng dụng để giải quyết các vấn đề về số, xử lý văn bản,

tạo ra trò chơi, và nhiều thứ khác.

· Có các môi trường lập trình đồ họa như Visual Java, Symantec Cafe,

Jbuilder, Jcreator, ...

· Có khả năng truy cập dữ liệu từ xa thông qua cầu nối JDBC (Java DataBase

Connectivity)

· Hỗ trợ các lớp hữu ích, tiện lợi trong lập trình các ứng dụng mạng (Socket)

cũng như truy xuất Web.

· Hỗ trợ lập trình phân tán (Remote Method Invocation ) cho phép một ứng

dụng có thể được xử lý phân tán trên các máy tính khác nhau.

· Luôn được bổ sung các tính năng cao cấp khác trong các phiên bản sau.

Những đặc điểm của ngôn ngữ Java:

· Ngôn ngữ hoàn toàn hướng đối tượng.

· Ngôn ngữ đa nền cho phép một chương trình có thể thực thi trên các hệ điều

hành khác nhau (MS Windows, UNIX, Linux) mà không phải biên dịch lại

Trang 48

chương trình. Phương châm của java là "Viết một lần , Chạy trên nhiều nền"

(Write Once, Run Anywhere).

· Ngôn ngữ đa luồng, cho phép trong một chương trình có thể có nhiều luồng

điều khiển được thực thi song song nhau, rất hữu ích cho các xử lý song

song.

· Ngôn ngữ phân tán, cho phép các đối tượng của một ứng dụng được phân bố

và thực thi trên các máy tính khác nhau.

· Ngôn ngữ động, cho phép mã lệnh của một chương trình được tải từ một máy

tính về máy của người yêu cầu thực thi chương trình.

· Ngôn ngữ an toàn, tất cả các thao tác truy xuất vào các thiết bị vào ra đều

thực hiện trên máy ảo nhờ đó hạn chế các thao tác nguy hiểm cho máy tính

thật.

· Ngôn ngữ đơn giản, dễ học, kiến trúc chương trình đơn giản, trong sáng.

2.3. Máy ảo java và trình biên dịch

Để đảm bảo tính đa nền, Java sử dụng cơ chế máy ảo của Java. ByteCode đó

là ngôn ngữ máy của máy ảo Java tương tự như các lệnh nhị phân của các máy tính

thực. Một chương trình sau khi được viết bằng ngôn ngữ Java (có phần mở rộng là

.java) phải được biên dịch thành tập tin thực thi được trên máy ảo Java (có phần mở

rộng là .class). Tập tin thực thi này chứa các chỉ thị dưới dạng mã Bytecode mà máy

ảo Java hiểu được phải làm gì. Khi thực hiện một chương trình, máy ảo Java lần

lượt thông dịch các chỉ thị dưới dạng Bytecode thành các chỉ thị dạng nhị phân của

máy tính thực và thực thi thực sự chúng trên máy tính thực. Máy ảo thực tế đó là

một chương trình thông dịch. Vì thế các hệ điều hành khác nhau sẽ có các máy ảo

khác nhau. Để thực thi một ứng dụng của Java trên một hệ điều hành cụ thể, cần

phải cài đặt máy ảo tương ứng cho hệ điều hành đó.

Bộ phát triển ứng dụng Java (JDK- Java Development Kit) JDK là một bộ

công cụ cho phép người lập trình phát triển và triển khai các ứng dụng bằng ngôn

ngữ java được cung cấp miễn phí bởi công ty JavaSoft (hoặc Sun). Có các bộ Jdk

cho các hệ điều hành khác nhau. Các phiên bản của JDK không ngừng được phát

Trang 49

hành, người lập trình có thể tải tại địa chỉ

http://www.oracle.com/technetwork/java/javase/downloads/index.html.

Cài đặt bộ phát triển ứng dụng JDK:

Các bước cài đặt bộ JDK trên nền windows như sau:

· Chạy tập tin Setup.exe

· Chọn nơi cài đặt, giả sử D:\jdk1.4

· Đặt biến môi trường

- PATH = D:\jdk1.4\bin; để có thể thực thi các chương trình này từ

bất kỳ thư mục hiện hành nào.

- CLASSPATH = D:\jdk1.4\lib;.; chỉ đến các lớp thư viện của Java

trong thư mục D:\jdk1.4\lib và các lớp tại thư mục hiện hành, thể hiện

bằng dấu chấm( . )

Bộ công cụ này gồm các chương trình thực thi đáng chú ý sau:

· javac: Chương trình biên dịch các chương trình nguồn viết bằng ngôn ngữ

java ra các tập tin thực thi được trên máy ảo Java.

· java: Đây là chương trình làm máy ảo của Java, thông dịch mã Bytecode

của các chương trình kiểu application thành mã thực thi của máy thực.

· appletviewer: Bộ thông dịch, thực thi các chương trình kiểu applet.

· javadoc: Tạo tài liệu về chú thích chương trình nguồn một cách tựđộng.

· jdb: Trình gỡ rối.

· rmic: Tạo Stub cho ứng dụng kiểu RMI.

· rmiregistry: Phục vụ danh bạ (Name Server) trong hệ thống RMI

2.4. Biên soạn chương trình bằng phần mềm Notepad của Ms Windows

2.4.1. Soạn thảo chương trình nguồn:

Notepad là trình soạn thảo đơn giản có sẵn trong MS Windows mà người lập

trình có thể dùng để biên soạn chương trình HelloWorld. Hãy thực hiện các bước

sau:

· Chạy chương trình Notepad: Chọn menu

Start\Programs\Accessories\Notepad

· Nhập nội dung sau vào Notepad:

Trang 50

public class HelloWorld { public static void main(String args[]) {

System.out.print("Hello World! \n");

} }

· Save tập tin với tên HelloWorld.java

- Chọn menu File \ Save

- Tại cửa sổ Save As hãy nhập vào: Save in: Thư mục nơi sẽ lưu tập tin File

Name: HelloWorld.java Save as type: All Files Nhấp vào nút Save

2.4.2. Biên dịch và thực thi chương trình

B1: Mở cửa sổ MS-DOS: Chọn menu Start\Programs\Accessories\Command

Prompt.

B2: Chuyển vào thư mục chứa tập tin HelloWorld.java

B3: Dùng chương trình javac để biên dịch tập tin HelloWorld.java:

javac HelloWorld.java

- Nếu có lỗi, trên màn hình sẽ xuất hiện thông báo lỗi với dấu ^ chỉ vị trí lỗi.

- Nếu không có lỗi, tập tin thực thi HelloWorld.class được tạo ra.

B4: Thực thi chương trình HelloWorld.class:

java HelloWorld

Kết quả màn hình như sau:

2.5. Các khái niệm cơ bản của ngôn ngữ java

Trang 51

Các khái niệm cơ bản được trình bày sau đây cũng là các khái niệm chung trong lập

trình hướng đối tượng:

l. Đối tượng (object),

2. Lớp đối tượng (class),

3. Trìu tượng hóa đã liệu (Data Abstraction),

4. Bao bọc và che giấu thông tin (EncapSulation and Information Hiding).

5. Mổ rộng, kế thừa giữa các lớp (Inheritance),

6. Đa Xạ và nạp chồng (Polymorphism and Overloading),

7. Liên kết động (Dynamic Binding),

8. Truyền thông điệp (Message Passing).

2.5.1. Đối tượng

Đối tượng là khái niệm cơ sở, quan trọng nhất của cách tiếp cận hướng đối

tượng.

Ðối tượng là thưc thể của hệ thống, của CSDL và được xác định thông qua

định danh ID (IDentifier) của chúng. Mỗi đối tượng có tập các đặc trưng bao gồm

cả các dữ liệu thành phần hay các thuộc tính mô tả các tính chất và các phương

thức. Các thao tác trên các dữ liệu để xác định hành vi của đối tượng đó.

Đối tượng là những thưc thể được xác định trong thời gian hệ thống hướng đối

tượng hoạt động. Như vậy đối tượng có thể biểu diễn cho người, vật, hay một bảng

dữ liệu hoặc bất kỳ một hạng thức nào đó cần xử lý trong chương trình, đối tượng

cũng có thể là các dữ liệu được định nghĩa bởi người sử dụng (người lập trình) như

vector, danh sách, các record, ... Nhiệm vụ của LTHĐT là phân tích bài toán thành

các đối tượng và xác định được bản chất của sự trao đổi thông tin giữa chúng. Đổi

tượng trong chương trình cẩn phải được chọn sao cho nó thể hiện được một cách

gấn nhất nội những thực thể có trong hệ thống thực.

Như vậy, đối tượng được định nghĩa một cách trừu tượng như là một khái

niệm, một cấu trúc gộp chung cả phần dữ liệu (thuộc tính) với các hàm (phương

thức) thao tác trên những dữ liệu đó và có thể trao đổi với những đối tượng khác.

Theo quan điểm của người lập trình, đối tượng được xem như là vùng bộ nhớ được

Trang 52

phân chia trong bộ nhớ máy tính để lưu trữ dữ liệu và tập các hàm tác động trên dữ

liệu gắn với chúng.

2.5.2. Lớp đối tượng

Lớp là bản mẫu hay một kiễu chung cho tất cả những đối tượng có những đặc

trưng giống nhau, nghĩa là có các thuộc tính và hành vi giống nhau. Đối tượng chính

là thể hiện (cá thể) của một lớp xác định. Trong lập trình hướng đối tượng, lớp được

xem là đồng nhất với kiếu (dữ liệu trừu tượng (ADT - Abstract Data Type được

Barbara đề xuất vào những năm 70).

Phương pháp lập trình hướng đối tượng là cách phân chia chương trình thành

các đơn thể (các lớp) bằng cách tạo ra các vùng bộ nhớ cho cả dữ liệu lẫn hàm và

chúng sẽ được sử dụng như các mẫu để tạo ra bản sao từng đối tượng khi chúng

được tạo ra trong hệ thống.

Nhiệm vụ của người lập trình là tìm cách xác định đầy đủ, chính xác danh

sách các lớp (đại diện cho tấtt cả các thưc thể trong hệ thống và mối quan hệ giữa

các lớp đối tượng đó.

Như vậy, lớp chính là tập các đối tuợng có cùng các thuộc tính và hành vi

giống nhau. Các thành phần của lớp có thể chia thành ba vùng quản lý chính: công

khai (public), được bảo vệ (protected) và vùng riêng (private). Trong ngôn ngữ mô

hình hóa thống nhất UML, cấu trúc của lớp thường được đặc tả bởi: tên của lớp, tập

các thuộc tính và tập các hàm.

2.5.3. Trìu tượng hóa dữ liệu

Trừu tượng hóa là cách biểu diễn những đặc tính chính và bỏ qua những chi

tiết. Trừu tượng hóa là sự mở rộng khái niệm kiểu dữ liệu và cho phép định nghĩa

những phép toán trừu tượng trên các dữ liệu trừu tượng.

Để xây dựng các lớp, chúng ta phải sử dụng khái niệm trừu tuợng hóa. Ví dụ,

chúng ta có thể định nghĩa một lớp là danh sách các thuộc tính trừu tượng như là

kích thước, hình dáng, mẫu và các hàm xác định trên các thuộc tính này để mô tả

các đối tượng trong không gian hình học. Trong lập trình, lớp được sử dụng như

kiểu dữ liệu trừu tượng.

Trang 53

Khi xây dựng phần mềm thì nguyên lý trừu tượng hóa được thưc hiện thông

qua việc trừu tượng hóa các chức năng, hàm (thuật toán) và trừu tượng hóa các kiểu

dữ liệu nguyên thủy.

2.5.4. Bao bọc và che dấu thông tin

Việc đóng gói dữ liệu và các hàm vào một đơn vị cấu trúc (gọi là lớp) được

xem như một nguyên tắc bao bọc thông tin. Kỹ thuật này cho phép xác định các

vùng đặc trưng riêng, công khai hay được bảo vệ bao gồm cả dữ liệu và các câu lệnh

nhằm điều khiển hoặc hạn chế những truy nhập tùy tiện của những đối tượng khác.

Dữ liệu được tổ chức sao cho thế giới bên ngoài (các đối tượng ở lớp khác) không

truy nhập được vào những thuộc tính riêng và chỉ cho phép các hàm trong cùng lớp

hoặc trong những lớp có quan hệ kế thừa với nhau mới được quyền truy nhập đến

vùng được bảo vệ.

Vùng công khai của lớp thì cho phép mọi đối tượng được phép truy nhập.

Chính các hàm thành phần công khai của lớp sẽ đóng vai trò như là giao diện giữa

các đối tượng và với phần còn lại của hệ thống. Nguyên tắc bao học dữ liệu để ngăn

cấm sự truy nhập trực tiếp trong lập trình được gọi là sự che giẫu thông tin.

Nguyên lý bao học che giấu thông tin của lớp đối tượng được mô tả như trong hình

sau:

Hình 2.3. Bao bọc và che giấu thông tin của lớp đối tượng

2.5.5. Sự mở rộng, kế thừa giữa các lớp

Trang 54

Nguyên lý kế thừa cho phép các đối tượng của lớp này được quyển sử dụng

một số tính chất (cả dữ 1iệu và các hàm thành phần) của các lớp khác. Một lớp có

thể là lớp con (lớp dẫn xuất) của một lớp khác, nghĩa là có thể bổ sung thêm một số

tính chất để thu hẹp phạm vi xác định các đối tượng trong lớp mới cho phù hợp với

ngữ cảnh trong thực tế.

Theo nguyên lý chung của kế thừa thì chỉ những thuộc tính, hàm thành phần

được bảo vệ và công khai là được quyền kế thừa, còn những thuộc tính, hàm thành

phần riêng là không được phép kế thừa. Những thuộc tính và hàm được kế thừa từ

1ớp chủ (lớp cơ sở) được xem như là “tài sản" của chính các đối tượng con cháu,

chúng có quyển sử dụng mà không cấn phải khai báo hay định nghĩa lại. Như vậy,

nguyên lý kế thừa trong lập trình hướng đối tượng hoàn toàn đồng nhất với nguyên

lý kế thừa gia sản trong xã hội loài người.

Phượng pháp hướng đối tượng nói chung hỗ trợ hai nguyên lý kế thừa: kế thừa đơn

và kế thừa bội. Kế thừa đơn là một lớp có thể kế thừa tư một lớp cơ sở, còn kế thừa

bội là một lớp có thể kế thừa từ nhiều hơn một lớp cơ sở. Ngôn ngữ C++ hỗ trợ cả

hai nguyên lý kế thừa, nhưng java chỉ hỗ trợ thực hiện kế thừa đơn.

Nguyên lý kế thừa đơn hỗ trợ cho việc tạo ra cấu trúc cây phân cấp các lớp.

Ví dụ, một trường đại học đào tạo sinh viên có ba khoa: Kim& Xã hội, Khoa Công

nghệ Thông tin và Khoa Toán, có thể xây dưng lớp Sinh viên là lớp cơ sở để từ đó

xây dụng tiếp ba lớp kế thừa là: Khoa Xã hội, Khoa Toán và Khoa CNTT hệ thống

sẽ được thiết kế thành các mức kế thừa và được mô tả trong UML như sau:

Hình 2.4. Cấu trúc phân cấp các lớp theo quan hệ kế thừa

Trang 55

Trong LTHĐT, khái niệm kế thừa kéo theo ý tưởng sử dụng lại. Nghĩa là từ

một lớp đã được xây dựng có thể bổ sung thêm một số tính chất để tạo ra một lớp

mới kế thừa lớp cũ mà không làm thay đổi những cái đã có.

Khái niệm kế thừa được hiểu như cơ chế sao chép ảo không đơn điệu. Trong thưc

tế,

mọi việc xảy ra tựa như những lớp cơ sở đều được sao vào trong lớp con (lớp đẫn

xuất) mặc đù điều này không được cài đặt tường minh (nên gọi là sao chép ảo) và

việc sao chép chỉ thực hiện đối với những thông tin chưa được xác định trong các

lớp cơ sở (sao chép không đơn điệu). Do vậy, có thể diễn đạt cơ chế kế thừa như

sau:

1. Lớp A kể thừa lớp B sẽ có (không tưởng minh) tất cả các thuộc tính, hàm

đã được xác định trong B ở những vùng được phép kế thừa (được bảo vệ,

công khai),

2. Bổ sung thêm một số thuộc tính, hàm để mô tả được đúng các hành vi của

những đối tượng mà lớp A quản lý.

2.5.6. Đa xạ ( tương ứng bội) và nạp chồng

Một khái niệm quan trọng nữa trong LTHĐT là khái niệm đa xạ tương tự như

trong toán học. Đa xạ là kỹ thuật được sử dụng để mô tả khả năng gửi một thông

điệp chung tới nhiều đối tượng mà mỗi đối tượng lại có cách :cả lý riêng theo ngữ

cảnh của mình.

Ða xạ đóng một vai trò quan trọng trong việc tạo ra các đối tượng có cấu trúc

với những nội dung thực hiện khác nhau mà lại có khả năng sử dụng chung một giao

diện (cùng một tên gọi). Theo một nghĩa nào đó, đa xạ là sự mở rộng khái niệm sử

dụng lại trong nguyên lý kế thừa. Hình 2.5 cho thấy hàm có tên là Ve() có thể sử

dụng để vẽ các hình khác nhau phụ thuộc vào đối tượng là các hình khi gọi để thực

hiện.

Tam giác, Hình tròn và Hình chữ nhật là các lớp con của lớp Hình. Hàm

Ve() là hàm đa xạ và nó được xác định tùy theo ngữ cảnh khi sử dụng, khi gọi thực

hiện đối tượng là tam giác thì sẽ vẽ tam giác, nếu đối tượng là hình tròn thì vẽ hình

tròn, v.v.

Trang 56

Hình 2.5. Tương ứng bội của hàm ve()

Nạp chồng (Overloading) là một trường hợp của đa xạ. Nạp chồng là khả

năng của một khái niệm (như các phép toán chẳng hạn) có thể được sủ dụng với

nhiều nội dung thực hiện khác nhau tùy theo ngữ cảnh, cụ thể là tùy thuộc vào kiểu

và số các tham số của chúng. Ví dụ, hàm cong() có thể được nạp chồng để cộng các

số nguyên (trừ), số thực (float), số phức (complex) hoặc ghép các xâu ký tự (String)

v.v.

int Cong(int, int); // Cộng hai số nguyên

float Cong(float, float); //' Cộng hai số thực

Complex Cong(Complex, Complex); // Cộng hai số phức

String Cong(String, String); // Ghép hai xâu

String Cong(String, int); // Ghép một xâu với một số nguyên

2.5.7. Liên kết động

Liên kết thông thường (liên kết tĩnh) là dạng liên kết được xác định ngay khi

dịch chương trình. Hầu hết các chương trình được viết bằng Pascal, C đều là dạng

liên kết tĩnh. Liên kết động là dạng liên kết các hàm, chức năng khi chương trình

thực hiện các lời gọi các hàm, chức năng đó. Như vậy, trong liên kết động, nội dung

của đoạn chương trình ứng với chức năng, hàm sẽ không được xác định cho đến khi

thực hiện lời gọi tới chức năng, hàm đó. Liên kết động liên quan chặt chẽ với những

khái niệm đa xạ và kế thừa trong lập trình hướng đối tượng. Chính nhờ khái niệm

liên kết động mà nhiều khái niệm của lập trình hướng đối tượng như khái niệm đa

xạ thực hiện được.

Chúng ta hãy xét Ve() trong hình 2.6. theo nguyên lý kế thừa thì mọi đối tượng

đều có thể sử dụng hàm này để vẽ các hình cụ thể khi hệ thống thực hiện. Hàm Ve()

Trang 57

được định nghĩa lại ở trong các lớp dẫn xuất để vẽ tam giác, hình tròn hay hình chữ

nhật theo các thuật toán tương ưng. Khi thưc hiện, ví dụ: nếu đối tượng hình là Hình

tròn thì hệ thống sẽ liên kết với hàm Ve() được định nghĩa trong lớp Hình tròn để vẽ

hình tròn.

2.5.8. Truyền thông điệp

Chương trình hướng đối tượng (được thiết kế và lập trình theo phương pháp

hướng đối tượng bao gồm một tập các đối tượng và mối quan hệ giữa các đối tượng

đó với nhan. Vì vậy, lập trình trong ngôn ngữ hướng đối tượng bao gồm các bước

sau:

l. Tạo ra các lớp đối tượng và mô tả hành vi của chúng;

2. Tạo ra các đối tượng theo định nghĩa của các lớp;

3. Xác định sự trao đổi thông tin giữa các đối tượng trong hệ thống.

Các đối tượng gửi và nhận thông tin trong hệ thống hướng đối tượng cũng

giống như con người trao đổi với nhau trong xã hội. Chính nguyên lý trao đổi thông

tin bằng cách truyền thông điệp cho phép chúng ta đễ dàng xây dựng được hệ thống

mô phỏng gần hơn với thực tế. Truyển thông điệp cho một đối tượng tức là báo cho

nó phải thực hiện một việc, một yêu cầu (thỉnh cầu) nào đó. Cách ứng xử của đối

tượng sẽ được mô tả ở trong lớp thông qua các hàm công khai (hay còn được gọi là

lớp dịch vụ).

Trong chương trình, thông điệp gửi đến cho một dối tuợng chính là để yêu

cầu thực hiện một công việc cụ thể, nghĩa là sử dụng những hàm tương ứng để xử lý

dữ liệu đã được khai báo trong lớp đối tượng đó. Vì vậy, trong thông điệp phải chỉ

ra được hàm cần thực hiện của đối tượng nhận thông điệp. Hơn thế nữa, thông điệp

truyền đi phải xác định tên đối tượng, tên hàm (thông diệp) và thông tin truyền đi.

2.5.9. Các ưu điểm của lập trình hướng đối ượng

Như trên đã phân tích lập trình hướng đối tượng đem lại một số lợi thế cho cả

người thiết kế lẫn người lập trình. Cách tiếp cận hướng đối tượng giải quyết được

nhiều vấn đề tồn tại trong quá trình phát triển phần mềm và tạo ra được những sản

phẩm phền mềm có chất lượng cao. Những phương pháp này mở ra một triển vọng

to lớn cho những người lập trình. Hy vọng sẽ có nhiều sản phẩm phần mềm tốt hơn

Trang 58

đáp ứng được những tính chất về sản phẩm chất lượng cao trong Công nghệ phần

mềm và nhất là bảo trì hệ thống ít tốn kém hơn. Những ưu điếm chính của LTHÐT

là:

l. Thông qua nguyên lý kế thừa chúng ta có thể loại bỏ được những đoạn mã

chương trình lặp lại trong quá trình mô tả các lớp và mở rộng khả năng sử

dụng các lớp đã được xây dựng.

2. Chương trình được này dựng từ những đơn thể (đối tượng) trao đổi với nhâu

nên việc thiết kế và lập trình sẽ được thực hiện theo quy trình nhất định chứ

không phải dựa vào kinh nghiệm và kỹ thuật như trước. Điều này đảm bảo rút

ngắn được thời gian xây dựng hệ thống và tăng năng suất lao động.

3. Nguyên lý che giấu thông tin giúp người lập trình tạo ra được những chương

trình an toàn không bị thay đổi bởi những đoạn chương trình khác một cách

tùy tiện.

hì.

4. Có thể xây dựng được ánh xạ các đối tượng của bài toán vào đối tượng của

chương trình.

5. Cách tiếp cận thiết kế đặt trọng tâm vào dữ liệu, giúp chúng ta xây dựng

được mô hình chi tiết và phù hợp với thực tế.

6. Những hệ thống hướng đối tượng dễ mở rộng, nâng cấp thành những hệ lớn

hơn.

7. Kỹ thuật truyền thông điệp trong việc trao đổi thông tin giữa các đối tượng

giúp cho việc mô tả giao diện với các hệ thống bên ngoài trở nên đơn giản hơn.

8. Có thể quản lý được độ phức tạp của những sản phẩm phần mềm.

9. Không phải trong hệ thống hướng đối tượng nào cũng có tất cả các tính chất

nêu trên. Khả năng xây dựng được chương trình có các tính chất đó còn phụ

thuộc vào lĩnh vực ứng dụng của dự án tin học và vào phương pháp thực hiện

của người phát triển phần mềm.

2.6. Các kiểu dữ liệu

2.6.1. Kiểu dữ liệu cơ sở

Kiểu số:

Trang 59

Tên kiểu Kích thước

byte 1 byte

short 2 bytes

int 4 bytes

long 8 bytes

float 4 bytes

double 8 bytes

Bảng 2.1. Kiểu dữ liệu số

Kiểu ký tự char: Java dùng 2 bytes cho kiểu ký tự, theo chuẩn mã UNICODE ( 127

ký tựđầu tương thích với mã ASCII ). Do đó, người lập trình sử dụng tương tự như

bảng mã ASCII.

Kiểu chuỗi ký tự String: thực chất đây là một lớp nằm trong thư viện chuẩn của

Java (Core API) java.lang.String

Kiểu logic (boolean): nhận 2 giá trị là : true và false.

Kiểu mảng:

Khai báo: int[] a ; float[] yt; String[] names;

hoặc: int a[]; float yt[]; String names[];

int maTran[][]; float bangDiem[][];

Khởi tạo: a = new int[3]; yt = new float[10]; names = new String[50]; maTran =

int[10][10];

Sử dụng mảng: int i = a[0]; float f = yt[9]; String str = names[20];

int x = matran[2][5];

Chú ý:

- Các giá trị kiểu dữ liệu nguyên thủy là nguyên thủy và không phải là đối tượng

- Mỗi kiểu giá trị nguyên thủy có miền giá trị xác định và các phép toán định nghĩa

trên các giá trị đó.

- Mỗi kiểu nguyên thủy có một lớp bao bọc gọi là lớp nguyên thủy. Thí dụ: kiểu int

thuộc lớp Integer, char thuộc lớp Char.

2.6.2. Quy ước đặt tên lớp, tên đối tượng, tên phương thức

Trang 60

Tên hằng, tên biến, tên lớp, tên phương thức , ... được đặt tên theo qui tắc bắt buộc

sau:

· Tên phân biệt giữa chữ hoa và chữ thường.

· Dùng các chữ cái, ký tự số, ký tự _ và $.

· Không bắt đầu bằng ký tự số.

· Không có khoảng trắng trong tên.

Để chương trình nguồn dễ đọc, dễ theo dõi trong lập trình hướng đối tượng còn sử

dụng quy ước đặt tên sau (không bắt buộc):

Tên lớp:

- Các ký tự đầu tiên của một từ được viết hoa, các ký tự còn lại viết thường.

-Ví dụ: lớp Nguoi, SinhVien, MonHoc, String, InputStream, OutputStream. .

.

Tên biến, tên hằng, tên phương thức:

- Từ đầu tiên viết thường.

- Ký tự đầu tiên của từ thứ hai trở đi được viết hoa.

Ví dụ: ten, ngaySinh, diaChi, inTen(), inDiaChi(), getInputStream(), . . .

- Vị trí đặt dấu { và } để bắt đầu và kết thúc các khối như sau: if (condition)

{ command1; command1; } else { command3; command4; }

2.7. Các từ khóa trong java

Các từ khóa của một ngôn ngữ lập trình là những định danh định sẵn được

định nghĩa trước của ngôn ngữ và không thể sư dụng cho những thực thể khác. Các

từ khóa của Java có thể chia thành 9 nhóm.

l. Tổ chức các lớp

package: Xác định một gói sẽ chứa một số lớp ở trong tệp nguồn.

import: Yêu cầu một hay một số lớp ở các gói chỉ định cần nhập vào để sử

dụng trong ứng dụng hiện thời.

2. Định nghĩa các lớp

interface: Định nghĩa các biển, hằng, phương thúc chung như là giao diện có

thể chia sẽ chung giữa các lớp.

Trang 61

class: Định nghĩa tuyển tập các thuộc tính dữ liệu, phương thức mô tả các đặc

tính và các hành vi của tập các đối tượng có quan hệ với nhau.

extends: Chỉ ra một lớp là mở rộng (kể thừa) của một lớp khác, hay còn gọi là

lớp con của lớp cho trước.

implements: Xây dụng một lớp mới cài đặt những phương thức từ interface xác

định trước.

3. Các từ khóa cho các biến và các lớp

abstract: Khai báo lớp trừu tượng không có thể hiện cụ thể,

public: Khai báo lớp, biến dữ liệu, phương thức công khai có thể truy nhập ở

mọi nơi trong hệ thống.

private: Khai báo biến dữ liệu, phương thức riêng trong từng lớp và chỉ cho

phép truy nhập trong lớp đó.

protected: Khai bào biến dữ liệu, phương thức được bảo vệ, cho phép truy

nhập ở lớp chứa chúng và các lớp con của lớp đó.

static: Ðinh nghĩa các biến, phương thức tĩnh của lớp, dùng chung cho tất cả

các đối tượng trong một lớp.

synchronized: Chỉ ra là ở mỗi thời điếm chỉ có một đối tượng hoặc một lớp có

thể truy nhập đến biến dữ liệu, hoặc phương thức loại đó nghĩa là chúng được đồng

bộ hóa.

volatile: Bảo cho chương trình dịch biết là biến khai háo Volatile có thể thay

đổi dị bộ (tùy ý) trong các luồng (thread).

final: Chỉ ra các biến, phương thức không được thay đổi sau khi đã được định

nghĩa.

native: Liên kết một phương thức với mã địa phương (native code), mã được

viết trong những ngôn ngữ lập trình khác như C chẳng hạn.

4. Các kiểu nguyên thủy (đơn giản)

long: Kiểu số nguyên lớn với các giá trị chiếm 64 bit (8 byte).

int: Kiểu số nguyên với các giá trị chiếm 32 bit (4 byte).

short: Kiểu số nguyên ngắn với các giá trị chiếm 16 bit (2 byte).

byte: Kiểu byte với các giá trị nguyên chiếm 8 bit (1 byte).

Trang 62

char: Kiểu ký tự Unicode, mỗi ký tự chiếm 16 bit (2 byte).

float: Kiểu số thực với các giá trị biểu diễn theo dạng dấu phẩy động 31 bit.

double: Kiểu số thực chính xác gấp đôi với các giá trị biểu điễn theo dạng dấu

phẩy động 64 hit (8 byte).

boolean: Kiểu logic với 2 trị: true, false.

void: Kiễu trống, sử dụng cho những hàm không trả lại giá trị.

5. Những từ khóa cho các giá trị và các biến

false: Giá trị kiểu boolean (sai)

true: Giá trị kiểu boolean (đúng).

this: Biến chỉ tới đối tượng hiện thời.

super: Biến chỉ tới đối tượng của lớp cha.

null: Chỉ ra đối tượng không tồn tại.

6. Xử lý ngoại lệ

throw, throws: Bỏ qua một ngoại lệ để xử lý sau.

try: Thử thực hiện cho đến khi gặp một ngoại lệ.

catch: Đón nhận một ngoại lệ.

finally: Thực hiện một khối lệnh đến cùng bất chấp các ngoại lệ có thể xảy ra.

7. Tạo lập và kiểm tra các đối tượng

new: Tạo lập một đối tượng.

instanceof: Kiểm tra xem một đối tượng có nằm trong một lớp hay một

interface hay không.

8. Dòng điều khiển

switch, case, default, if, else, break, continue, do, while, for, return.

2.8. Chú thích trong chương trình java (Comment)

Chú thích trên một dòng: // Lời chú thích

Chú thích trên nhiều dòng: /* lời chú thích */

2.9. Các phép toán cơ bản

Phép toán số học: +, - , *, / , % , =,++ , -- , += , - = , *= , /= , %=

Phép toán logic: ==, !=, && , ||, ! ,> , < , >= , <=

Phép toán trên bit : & , | , ^ , << , >> , ~

Trang 63

Phép toán điều kiện: ? :

Cách chuyển đổi kiểu: (Kiểu Mới)

2.10. Cấu trúc một chương trình java kiểu ứng dụng độc lập

Java là một ngôn ngữ thuần đối tượng (pure object). Tất cả các thành phần

được khai báo như hằng, biến, hàm thủ tục đều phải nằm trong phạm vi của một lớp

nào đó. Một ứng dụng trong Java là một tập hợp các lớp liên quan nhau, bao gồm

các được định nghĩa bởi người lập trình.

Trong một ứng dụng chỉ có một Lớp thực thi được. Đây là lớp đầu tiên được xem

xét đến khi thực thi ứng dụng. Lớp thực thi được này có các đặc điểm sau:

· Có tên lớp trùng với tên tập tin chứa nó.

· Phải khai báo phạm vi là public

· Có chứa phương thức: public static void main (String args[]){ . . . } là

phương thức được thực thi đầu tiên.

· Nếu nhiều lớp được định nghĩa trong một tập tin, chỉ có một lớp được khai

báo public.

Một số thí du:

Thí dụ 1: Hiển thị thông tin ra màn hình

Để in thông tin ra màn hình cần dùng phương thức : System.out.print(arg1+ arg2+ ..

+ argn) Java sẽ tự động định dạng dữ liệu cho các tham số arg1, arg2, ..., argn tùy

theo kiểu của chúng. Lưu chương trình sau vào tập tin Display.java:

public class Display {

public static void main(String args[]) {

int i = 10; String str = " nam yeu "; char ch = 'm';

System.out.print('\n'+ "Bai hat:" + i + str + ch);

} }

Biên dịch và thực thi cho kết quả:

Trang 64

Phương thức System.out.println(arg1+ arg2+ .. + argn) in các tham số và tự

động xuống dòng mới.

Thí dụ: Đọc ký tự từ bàn phím

Phương thức int System.int.read() trả một số nguyên là mã ASCII của ký tự nhập từ

bàn phím. Lưu chương trình sau vào tập tin KeyRead.java:

import java.io.*;

public class KeyRead {

public static void main(String args[]) {

try {

int ch = System.in.read();

System.out.print("Ky tu " + (char)ch + " co ma ascii = "+ch);

} catch(IOException ie) {

System.out.print("Error " + ie) ; } } }

Biên dịch và thực thi ta có kết quả:

Trang 65

Trong ví dụ trên lưu ý một số điểm sau:

· Dòng đầu tiên import java.io.*; là cơ chế để khai báo với trình biên dịch các

lớp thư viện của Java mà chương trình có sử dụng đến. Trong trường hợp này

chương trình khai báo sử dụng tất cả các lớp trong gói (package) java.io.

Thực tế chương trình trên chỉ sử dụng lớp IOException của gói java.io mà

thôi, vì thế có thể thay thế dòng java.io.*; bằng java.io.IOException;.

· Cơ chế ngoại lệ (Exception) của java: try { .... } catch(IOException ie) { ....

} sẽ được giải thích rõ ở phần sau.

2.11. Các cấu trúc điều khiển

2.11.1. Lệnh rẽ nhánh if

Cú pháp: if (biểu thức điều kiện) {

// Các lệnh sẽ được thực hiện nếu giá trị của biểu thức điều kiện là true

}

Hoặc:

if (biểu thức điều kiện) {

// Các lệnh sẽ được thực hiện nếu giá trị của biểu thức điều kiện là true

} else {

// Các lệnh sẽ được thực hiện nếu giá trị của biểu thức điều kiện là false

}

Thí dụ: Lưu chương trình sau vào tập tin IfDemo.java:

Trang 66

import java.io.*;

public class IfDemo {

public static void main(String args[]) {

System.out.print("Vui long nhap mot ky tu:");

try {

int ch = System.in.read(); if (ch == 'A') {

System.out.print("Ban rat may man !");

} else {

System.out.print("Ban khong gap may !");

} } catch(IOException ie) { System.out.print("Error:"+ie); } } }

2.11.2. Lệnh switch

Cú pháp:

switch ( variable ) {

case value1 : {

// Các tác vụ sẽ được thực thi nếu giá trị của variable là value1

break; }

case value2 : {

// Các tác vụ sẽđược thực thi nếu giá trị của variable là value2

break; }

. . .

default:

// Tác vụ sẽđược thực thi nếu giá trị của variable không là các giá trị

trên }

Thí dụ: Lưu chương trình sau vào tập tin CaseOp.java:

import java.io.*;

public class CaseOp {

public static void main(String args[]) {

System.out.print("Enter a number character: ");

try {

int ch = System.in.read();

Trang 67

switch(ch) {

case '0': { System.out.print("Zero");break;}

case '1': { System.out.print("One"); break;}

case '2': { System.out.print("Two"); break;}

case '3': { System.out.print("Three");break;}

case '4': { System.out.print("Four"); break;}

case '5': { System.out.print("Five"); break;}

case '6': { System.out.print("Six"); break;}

case '7': { System.out.print("Seven");break;}

case '8': { System.out.print("Eight");break;}

case '9': { System.out.print("Nine"); break;}

default: { System.out.print("I don't know"); break;}

} } catch(IOException ie) { System.out.print("Error "+ie); } } }

Biên dịch và thực thi được kết quả sau:

2.11.3. Lệnh while

Cú pháp:

while (biểu thức điều kiện) {

Các lệnh sẽ được thực hiện lặp lại nếu giá trị của biểu thức điều kiện đúng }

Thí dụ: Lưu chương trình sau vào tập tin WhileDemo.java:

import java.io.*;

Trang 68

public class WhileDemo {

public static void main(String args[]) {

int num = '9'; while (num > '0') {

System.out.print((char)num +" "); num--; } } }

2.11.4. Lệnh do - while

Cú pháp:

do {

// Lặp lại các tác vụ ở đây cho đến khi điều kiện condition có giá trị là false

} while (biểu thức điều kiện)

Thí dụ: Lưu chương trình sau vào tập tin DoWhileDemo.java:

import java.io.*;

public class DoWhileDemo {

public static void main(String args[]) {

int num = '9'; do {

System.out.print((char)num +" "); num--; }

while (num > '0'); } }

Biên dịch và thực thi được kết quả sau:

2.11.5. Lệnh for

Cú pháp:

for (biểu thức 1; biểu thức điều kiện; biểu thức 2){

Trang 69

// Các lệnh cần lặp lại

}

Thí dụ: Lưu chương trình sau vào tập tin ForDemo.java:

import java.io.*;

public class ForDemo {

public static void main(String args[]) {

for(int num = '9'; num>'0'; num --) {

System.out.print((char)num +" "); } } }

Biên dịch và thực thi được kết quả như sau:

2.11.6. Lệnh break

Vòng lặp của các lệnh while, do-while và for sẽ kết thúc khi lệnh break được thực

hiện. Thí dụ: Lưu chương trình sau vào tập tin BreakDemo.java:

import java.io.*;

public class BreakDemo {

public static void main(String args[]){

int num =Integer.valueOf(args[0]).intValue();

int i= num /2;

while(true){ if (num % i ==0) break; i--; }

System.out.println("So lon nhat chia het "+num+ " la: "+i); } }

Biên dịch và thực thi được kết quả sau:

Trang 70

Chương trình trên đổi đối số thứ nhất của nó (lưu trong args[0]) thành số (bằng lệnh

Integer.valueOf(args[0]).inValue() ) và tìm số lớn nhất chia hết số này.

2.11.7. Lệnh continue

Trong một lần lặp nào đó của các lệnh while, do-while và for, nếu gặp lệnh continue

thì lần lặp sẽ kết thúc (bỏ qua các lệnh phía sau continue) để bắt đầu lần lặp tiếp

theo.

Thí dụ: Lưu chương trình sau vào tập tin ContinueDemo.java:

import java.io.*;

public class ContinueDemo{

public static void main(String args[]){

int num =Integer.valueOf(args[0]).intValue();

System.out.print("The odd numbers: ");

for (int i =0; i< num; i++ ){

if (i % 2 ==0) continue; System.out.print(i+ " "); } } }

Biên dịch và thực thi được kết quả sau:

Trang 71

Chương trình này in ra tất cả các số lẻ nhỏ hơn số đưa vào từ đối số.

2.11.9. Phép toán ?

Cú pháp:

(biểu thức điều kiện) ? Operation1 : Operation2;

Nếu điều kiện biểu thức điều kiện có giá trị là true lệnh sẽ trả về giá trị của biểu

thức Operation1, ngược lại sẽ trả về giá trị của biểu thức Operation2.

Thí dụ: Lưu chương trình sau vào tập tin QuestionOp.java:

import java.io.*;

public class QuestionOp {

public static void main(String args[]) {

System.out.print("Vui long nhap mot ky tu:");

try { int ch = System.in.read();

int point = (ch == 'A') ? 10:0;

System.out.print("Diem cua ban la:"+point);

} catch(IOException ie) {

System.out.print("Error:"+ ie); } } }

2.11.10. Đọc đối số của chương trình

Khi thực thi chương trình ta có thể nhập vào các đối số từ dòng lệnh theo cú pháp

sau: java ClassName arg1 arg2 arg3 argn

Trang 72

Các đối số cách nhau khoảng trắng. Để đón nhận các đối số này, phương thức main

bắt buộc phải khai báo một tham số kiểu mảng các chuỗi public static void main(

String args[]) { … } Các đối số lần lượt được đặt vào các phần tử của mảng này. Số

lượng đối số có thể xác định được bằng cách truy xuất thuộc tính args.length của

mảng.

Thí dụ: Lưu chương trình sau vào tập tin PrintArgs.java:

public class PrintArgs {

public static void main (String args[]) {

for (int i = 0; i < args.length; i++) {

System.out.println(args[i]); } } }

Biên dịch và thực thi chương trình được kết quả sau:

2.11.11. Đổi chuỗi thành số

Lưu chương trình sau vào tập tin StringToNumber.java:

public class StringToNumber{

public static void main (String args[]) {

int i = Integer.valueOf(args[0]).intValue();

long l = Long.valueOf( args[1]).longValue();

float f = Float.valueOf( args[2]).floatValue();

System.out.println("Integer number = "+i );

System.out.println("Long number = "+l );

Trang 73

System.out.println("Float number = "+f ); } }

Biên dịch và thực thi chương trình được kết quả sau:

2.11.12. Ngoại lệ (EXCEPTION)

Trong chương trình, có một số các "thao tác không chắc chắn", ví dụ như các

thao tác vào/ra: đĩa mềm chưa sẵn sàng, máy in có lỗi, nối kết mạng không thực

hiện được . . . sẽ dẫn đến lỗi thực thi chương trình. Java hạn chế các lỗi sinh ra từ

"thao tác không chắc chắn" bằng cơ chế Ngoại lệ (Exception). Ngoại lệ tức là một

sự kiện xảy ra ngoài dự tính của chương trình nếu không xử lý sẽ làm cho chương

trình chuyển sang trạng thái không còn kiểm soát được. Thí dụ điều gì sẽ xảy ra nếu

chương trình truy xuất đến phần tử thứ 11 của một mảng 10 phần tử ? Một số ngôn

ngữ như C, C++ sẽ không báo lỗi gì cả, chương trình vẫn tiếp tục vận hành nhưng

kết quả thì không thể xác định được. Để hạn chế những lỗi như thế, Java bắt buộc

các lệnh có thể dẫn đến các ngoại lệ phải có các đoạn mã xử lý phòng hờ khi ngoại

lệ xảy ra theo cú pháp sau: try { Các thao tác vào ra có thể sinh ra các ngoại lệ. }

catch (KiểuNgoạiLệ_01 biến) { ứng xử khi ngoại lệ KiểuNgoaiLệ_01 sinh ra }

catch (KiểuNgoạiLệ_02 biến) { ứng xử khi ngoại lệ KiểuNgoaiLệ_02 sinh ra

}finally { Công việc luôn luôn được thực hiện }. Trong cơ chế này, các lệnh có thể

tạo ra ngoại lệ sẽ được đưa vào trong khối bao bọc bởi từ khóa try {}. Tiếp theo đó

là một loạt các khối catch{}. Một lệnh có thể sinh ra một hoặc nhiều loại ngoại lệ.

Ứng với một loại ngoại lệ sẽ có một khối catch{} để xử lý cho loại ngoại lệ đó.

Trang 74

Tham số của catch chỉ ra loại ngoại lệ mà nó có trách nhiệm xử lý. Khi thực thi

chương trình, nếu một lệnh nào đó nằm trong khối try{} tạo ra ngoại lệ, điều khiển

sẽ được chuyển sang các lệnh nằm trong các khối catch{} tương ứng với loại ngoại

lệ đó. Các lệnh phía sau lệnh tạo ra ngoại lệ trong khối try{} sẽ bị bỏ qua. Các lệnh

nằm trong khối finally{} thì luôn luôn được thực hiện cho dù có xảy ra ngoại lệ hay

là không. Khối lệnh finally{} là tùy chọn có thể không cần. Ngoại lệ có loại bắt

buộc phải xử lý, tức phải có try{}, có catch{} khi sử dụng lệnh đó. Ví dụ như lệnh

đọc từ bàn phím. Trình biên dịch của java sẽ báo lỗi nếu chúng ta không xử lý

chúng.

Ngược lại, có loại ngoại lệ không bắt buộc phải xử lý, ví dụ như truy xuất

đến phần tử bên ngoài chỉ số mảng. Tra cứu tài liệu đặc tả các API của java để biết

được các ngoại lệ tạo ra từ một phương thức.

Thí dụ: Lưu chương trình sau vào tập tin ExceptionDemo.java:

public class ExceptionDemo {

public static void main(String[] args) {

try { System.out.println("Hello " + args[0]); }

catch (ArrayIndexOutOfBoundsException e){

System.out.println("Hello Whoever you are."); }

finally { System.out.println("How are you?"); } } }

Biên dịch và thực thi có kết quả như sau:

Trang 75

Trong chương trình trên chúng ta dự định sẽ chào người được đưa vào từ đối

số thứ nhất của chương tình (được chứa trong phần tử args[0]). Tuy nhiên nếu người

dùng thực thi chương trình quên đưa vào đối số, tức phần tử args[0] không tồn tại.

Ngoại lệ báo hiệu truy xuất đến phần tử nằm ngoài mảng

(ArrayIndexOutOfBoundsException) được quẳng ra (throw). Khi đó đoạn mã lệnh

trong khối catch có tham số là loại ngoại lệ ArrayIndexOutOfBoundsException sẽ

được thực hiện.

2.12. Lớp và các thành phần của lớp đối tượng

2.12.1. Định nghĩa lớp

Ðịnh nghĩa một lớp là đặc tả một kiểu dữ liệu mới và mô tả cách cài đặt kiểu

dữ liệu

đó. Nó có cú pháp được qui định như sau:

[<Phạm vi hoặc kiểm soát truy nhập>] class <Tên lớp>

[extends <tên lớp cha>] [implements <tên giao diện>]{

<Các thành phẩn của lớp>

}

trong đó class , extends , imp1ements là các từ khoá. Những phần trong cặp [] là tùy

chọn.

<Các thành phần của lớp> bao gồm các biến, các phương thức (hàm) thành phần và

các toán tử tạo lập (Constructor).Thân của một lớp lại có thể chứa các khai báo của

các lớp, giao điện (interface) khác và xem chúng như là các. thành phần của lớp.

2.12.1. Định nghĩa hàm thành phần

Hành vi của các đối tượng của một lớp được xác định bởi các hàm thành phần

của lớp đó. Cú pháp để định nghĩa các hàm có dạng tổng quát:

|<Phạm vi hoặc thuộc tính kiểm soát truy nhập>] <Kiểu trả lại> <Tên hàm

>(

[<Danh sách tham biến hình thức>]) [<Mệnh đề throws>{

<Nội dung của hàm>

}

Trang 76

<Kiểu trả lại> có thể là kiểu nguyên thủy, kiểu lớp hoặc không có giá trị trả lại (kiểu

void).

<Danh sách tham biến hình thức> bao gồm dãy các tham biến (kiểu và tên) phân

cách với nhau bởi dấu phẩy.

Vi dụ: // Tệp Demo.java

public class Demo{

public static void main(String args [] ) {

if (args.length == 0) return; //Hàm kiểu void có thể sử dụng retum;

output (checkValue (args.length) ) ;

}

static void output (int value) {// Hàm kiểu void không cần sử dụng retum

System.out.println (value) ;

}

static int checkValue (int i) { // Hàm khác kiểu void phải sử dụng return để

trả

if (i > 3) return 1; // lại giá trị,

else return 2 ;

} }

2.12.3. Nạp chồng các thành phần của hàm

Mỗi hàm đều có phần định danh hàm, bao gồm tên của hàm, kiểu trả lại giá trị

và dạnh sách các tham biến. Trong lập trình huớng đối tượng cho phép sử dụng

cùng một tên hàm nhưng định nghĩa nhiều nội dung thực hiện khác nhau. Những

hàm như thế được gọi là hàm nạp chồng hay hàm tải bội (Overloading).

Lưu ý: Cơ chế nạp chồng cho phép một hàm có cùng một tên gọi nhưng danh sách

tham biến khác nhau, do vậy sẽ có các định danh khác nhau. Những hàm được nạp

chồng với các định danh khác nhau có các phần cài đặt thực hiện những công việc

khác nhau và có kiểu trả lại khác nhau.

JDK API đã xây dựng rất nhiều hàm được nạp chồng. Ví dụ, lớp java.lang.Math có

hàm nạp chồng min() xác định giá trị cực tiểu của 2 số:

public static double min(double a, double b)

Trang 77

public Static float min(float a, float b)

public static int min(int a, int b)

public static long min(long a, long b)

Cũng cần lưu ý là danh sách tham biến của các hàm nạp chồng phải khác nhau về số

lượng hoặc về thứ tự các kiểu của các tham biến.

2.12.4. Viết đè các hàm thành phần và cơ chế che bóng của các biến

Trong nhiều trường hợp, một lớp con có thể viết đề, thay đổi nội đung thực

hiện của những hàm được thừa kế từ lớp cha. Khi những hàm này được gọi để thực

hiện đối với những đối tượng của lớp con thì nội dung được định nghĩa mới ớ lớp

con sẽ được thực thi.

Chú ý:

· Định nghĩa mới của hàm viết đè phải có cũng định danh (tên gọi và danh

sách tham biến) và cùng kiểu trả lại giá trị.

· Định nghĩa mới của hàm viết đề trong lớp con chỉ có thể xác định tất cả hoặc

tập con các lớp ngoại lệ được kể ra trong mệnh đề cho qua ngoai lệ.

· Định nghĩa của những hàm sẽ viết đè không được khai báo final ở lớp cha.

Ví dụ 4.2. Viết đề và nạp chồng các hàm thành phần

// Khachhang.java

import java . io. *;

protected String loaiHoaDon = “Hoa don nho”; //(1)

protected double docHoaDon(int giaDien) throws Exception { //(2)

double soGio = 10.0;

hoaDonNho = giaDien* soGio;

System.out.println(loaiHoaDon + hoaDonNho)

return hoaDonNho;

}}

class DenTuyp extends Den {

public String 1oaiHoaDon =“Hoa don lon”; //Bị che bóng (3)

public double docHoaDon (int giaDien) throws Exception { //viết đè hàm (4)

double soGio = 100.0,

Trang 78

hoaDonLon = giaDien* soGio;

System.out.print1n(loaiHoaDon + hoaDonLon);

return hoaDonLon;

}

public double docHoaDon (){

System.out.println(“Khong-co hoa don!");

return 0.0;

}}

public class KhachHang {

public static void main{String args[]) throws Exception { //6

DenTuyp denl = new DenTuyp ( ) ; //7

Den den2 = den1; //8

Den den3 = new Den(); //9

// Gọi các hàm đã viết đè

den1.docHoaDon(l000); //10

den2.docHoaDon(10000; //11

den3.docHoaDon(1000); //12

// Truy nhập tới các biến thành phần đã bị viết đè (bị che bóng)

System.out.println(den1.loaiHoaDon(); //13

SyStem.out.print1n(den2.loaiHoaDon(); //14

System.out .print ln (den3.loaiHoaDon() ; //15

//Gọi các hà nạp chồng

den1.docHoaDon();

Kết quả thực hiện của chương trình KhachHang:

Hoa don lon: 10000000

Hoa don lon: 100000.00

Hoa don nho: 10000.00

Hoa don lon:

Hoa don nho:

Hoa don nho:

Trang 79

Khong co hoa don!

Hàm docHoaDon() của lớp cha Den được định nghĩa ở (2) và sau đó được

viết đè trong lớp con DenTuyp ở (4). Những hàm này sẽ bỏ qua ngoại lệ Exception

(lớp thư

viện ở gói java.io.*). Phạm vi lớp của docHoaDon() có thể thay đổi, ví dụ, chuyển

từ protected sang public, và tham biến cũng có thể khai báo final, ví dụ final int

giaDien. Lời gọi hàm docHoaDon() thực hiện đối với đối tượng của lớp con

DenTuyp và lớp cha Den ở (10) và (11) tương ứng, kết quả thực hiện nội dụng đã

viết đè ở (4).

Lời gọi hàm docHoaDon() đối với đối tượng của lớp cha (lớp Den) ỗ (12) tất

nhiên sẽ thực hiện nội dung được định nghĩa ở (2).

Lưu ý: Các hàm final, static không được phép viết đè.

Cơ chế che bóng của các biến:

Về nguyên tắc, một lớp con không được phép viết đè các biến thành phần của

lớp cha, nhưng có thể bị che khuất chúng tương tư như biến cục bộ trong lớp con.

Lớp con có thể định nghĩa lại (che) các biến đã được định nghĩa trong lớp cha. Khi

đó các biến này của lớp cha sẽ không thể truy nhập trực tiếp theo tên ở lớp con.

Trong hàm của lớp con có thể sử dụng toán tử super() để truy nhập tới các biến của

lớp cha bị che khuất.

Trong ví dụ 4.2, biến loaiHoaDon được định nghĩa lại ở lớp con DenTuyp (B),

do vậy với lệnh (13) thì den1.loaiHoaDon sẽ cho kết quả đã định nghĩa lại ở (3).

Nhưng 2 đối tượng den2, den3 lại thuộc lớp cha Den do đó vẫn giữ nguyên

loaiHoaDon của lớp cha được định nghĩa ở (l).

Viết đè và nạp chồng là khác nhau:

Viết đè: yêu cầu cùng định danh hàm (cũng tên gọi, cùng danh sách tham số)

và cũng kiểu trả lại kết quả đã được định nghĩa tại lớp cha.

Nạp chồng yêu cầu khác nhau về định danh nhưng giống nhan về tên gọi của hàm.

Vì thế chúng sẽ khác nhau về số lượng, kiểu, hay thứ tự của các tham biến.

Hàm có thể nạp chồng ở trong cùng lớp hoặc ở các lớp con cháu.

Trang 80

Từ những lớp con khi muốn gọi tới các hàm ở lớp cha mà bị viết đè thì phải

gọi qua toán từ đại diện cho lớp cha, đó là super(). Ðối với hàm nạp chồng thì lại

không cần như thế. Lời gọi hàm nạp chồng được xác định thông qua danh sách các

đối số hiện thời sánh với đối số hình thức: để xác định nội dung tương ứng.

2.13. Phạm vi và các thuộc tính kiểm soát truy nhập các thành phần của lớp

4.13.1. Phạm vi của các thành phần

Phạm vị của các thành phần có 2 loại:

- Phạm vi lớp

- Phạm vi khối của các biến cục bộ (local) .

1 / Phạm vi lớp

Phạm vi lớp xác định những thành phần được truy nhập bên trong của một lớp (kể

cả lớp được kế thừa). Quyền truy nhập của chúng thường được xác định thông qua

các bổ ngữ: public, protected, private.

Vi dụ. Phạm vi lớp của các thành phần

class BongDen{

//các biến thành phần

private int sowatts; // số watt của bống

private boolean batTat; //true – bóng sáng; false - bóng tắt

private String viTri; // Nơi đặt bóng đèn

// Các hàm thành phần

public void batDen() {batTat = true;} // Bật đèn

public void tatDen() {onOff = fa1se;} //Tắt đèn

public boolean tatHaySang(){return batTat;}

public BongDen nhanDoi (BongDen bongCu){ //(1)

BongDen bongMoi = new BongDen();

bongMoi.sOWatts = bongCu.sOWatts; //(2)

bongMoi.batTat = bongCu.bat'I‘at; //(3)

bongMoi.viTri = new String(bongCu.vi'1‘ri); //(4)

}}

2/ Phạm vi khối

Trang 81

Trong chương trình, các lệnh khai báo và các lệnh thực hiện có thể gộp lại thành

từng khối (block) bằng cách sử dụng cặp dấu {, }. ( Thân của hàm, của lớp cũng là

một khối. Các khối có thể lồng nhau và khi đó luật phạm vi được áp dụng cho các

biến cục bộ. Luật phạm vi phát biểu tổng quát là một biến được khai báo ở trong

một khối có phạm vi xác định bên trong khối và không xác định ở bên ngoài khối

đó.

Lưu ý:

· Trong cùng một phạm vì không thể khai báo một biến hai lần. Các tham biến

cũng không thể khai báo lại trong thân của hàm. Lưu ý là trong các khối thì

lệnh khai báo là tự do, thứ tự không quan trọng, muốn khai báo ở chỗ nào

cũng được miễn là phải khai báo trước khi sử dụng.

· Phạm vi khối của biến được xác định kể từ chỗ bắt đầu khai báo cho đến kết

thúc khối (gặp dấu ngoặc } tương ứng).

· Có thể có nhiều khối lồng nhau nhưng không được cắt nhau và những biến

khai báo ở khối ngoài đều có phạm vi xác định ở trong mọi khối bao bên

trong nó.

2.13.2. Các thuộc tính kiểm soát truy cập các thành phần của lớp

a. Các thành phần được khai báo public: Các thành phần này cho phép truy nhập

mọi nơi trong hệ thống, kể cả các lớp trong cùng gói hoặc khác gói.

Thí dụ:

SuperclassA..java // (1)

package goiA;

public class SuperclassA{

public int superclassVarA; // (2)

public void superc1assMethodA(){ /* . . .*/} // (3)

}

class SubclassA extends SuperclassA{

void subc1assMethod.A() {s1*.perc1assVarA = 20; } // (4)

}

class AnyClassA{

Trang 82

SuperclassA obj = new SuperclassA{);

void anyClassMethodA() {

obj.superclassMethodA(); // (5)

}}

Tệp SuhclassB.java // (6)

package goiB;

import goiA . * ; // Nhập các lớp đã được định nghĩa ở gói A

public class Subc1assB extends SuperclassA{

void subclassMet:hodB () {superc1assMethod.A(} ;} // (7)

}

class AnyC1assB{

Superc1assA obj = new Sup rc1assA();

void anyC1assMethodB(){

obj.superclassVarA = 10; // (8)

}}

b. Các thành phần được khai báo protected: Các thành phần này cho phép truy nhập

đối với tất cả các lớp trong cùng gói, kể cả các lớp con.

c. Các thành phần được khai báo private: Các thành phần này được bảo vệ chặt chẽ

chỉ cho phép truy nhập đối với những đối tượng trong cùng lớp.

d. Các thành phần được khai báo static: Là những thành phần đại diện chung cho cả

lớp, được khởi tạo giá trị mặc định. Các thành phần không phải static thì mỗi biến

đều là bản sao có giá trị riêng cho từng đối tượng.

e. Các thành phần được khai báo final: Các biến final được xem như các hằng, giá

trị của chúng sẽ không thể thay đổi sau khi khởi tạo giá trị. Các hàm final thì không

được phép viết đè ở các lớp con cháu.

f. Các hàm được khai báo là abstract:

Cú pháp: abstract <kiểu> <tên_hàm(danh sách các đối số) [mệnh đề

throws]> ;

Các hàm asbtract được xem như khuôn mẫu, không có nội dụng xác định, nội

dung của nó sẽ được cài đặt cụ thể ở các lớp con cháu.

Trang 83

Các hàm trong lớp giao diện (Interface) đều là các hàm abstract.

g. Các lớp abstract: Các lớp này không có thể hiện cụ thể, thường được sử dụng để

tổng quát hóa các khái niệm, thực thể cụ thể trong thực tế.

Lớp abstract phải có ít nhất một hàm abstract.

h. Các thành phần đồng bộ synchronized: Java hỗ trợ cơ chế thực hiện đa luồng. Có

thể có nhiều luồng muốn thực hiện đồng thời trên cùng một đối tượng nào đó. Có

những loại thiết bị như máy in, kênh truyền đòi hỏi phải có cơ chế chỉ một luồng

được thực hiện, nghĩa là phải đồng bộ chúng.

2.14. Các kiểu ứng dụng

Khi bắt đầu thiết kế một ứng dụng dưới ngôn ngữ Java, người lập trình phải

chọn kiểu cho nó là Application hay Applet.

Applet (chương trình ứng dụng nhúng): Là một chương trình ứng dụng

được nhúng vào các trang web. Mã của chương trình được tải về máy người dùng từ

Web server khi người dùng truy xuất đến trang web chứa nó.

Application (chương trình ứng dụng độc lập): Là một chương trình ứng

dụng được thực thi trực tiếp trên các máy ảo của Java.

2.15. Làm việc với các stream

Stream là một dòng liên tục, có thứ tự các bytes dữ liệu chảy giữa chương trình

và các thiết bị ngoại vi. Nó là khái niệm trừu tượng giúp giảm bớt các thao tác vào

ra phức tạp đối với người lập trình. Nó cho phép nối kết nhiều loại thiết bị ngoại vi

khác nhau với chương trình. Nếu dòng dữ liệu trong Stream có hướng chảy từ thiết

bị ngoại vi vào chương trình thì ta nói đây là Stream nhập (Input Stream), ngược lại

là Stream xuất (Output Stream). Đối với Java, các thiết bị chỉ nhập, như bàn phím,

sẽ có các Stream nhập nối với nó, các thiết bị chỉ xuất, như màn hình, sẽ có các

stream xuất nối với nó, các thiết bị vừa xuất, vừa nhập, như đĩa từ, thì có cả stream

nhập và xuất nối với nó. Để giao tiếp với các thiết bị ngoại vi, chương trình trước

tiên phải lấy được các stream nhập/xuất gắn với thiết bị ngoại vi này. Sau đó,

chương trình có thể gởi dữ liệu ra ngoại vi bằng thao tác ghi vào Stream xuất của

ngoại vi. Ngược lại, chương trình có thể nhận dữ liệu từ ngoại vi bằng thao tác đọc

stream nhập của ngoại vi đó. Như vậy, chương trình chỉ làm việc trên các stream

Trang 84

nhập và stream xuất, mà không quan tâm đến đặc điểm riêng biệt của thiết bị ngoại

vi nối với Stream. Điều này giúp chương trình giao tiếp với hệ thống mạng cũng dễ

dàng như giao tiếp với màn hình, bàn phím hay đĩa từ.

Một điểm khác cần lưu ý là stream bao gồm những bytes rời rạc. Những bytes

này mô tả những dạng dữ liệu khác nhau. Ví dụ một số integer khi viết vào stream

sẽ chuyển thành 4 bytes. Vì thế cần phải có các thao tác chuyển đổi dữ liệu nhận và

gửi giữa chương trình và stream. Java hỗ trợ hai các lớp stream cơ bản trong gói

java.io là:

· java.io.InputStream: Stream nhập

· java.io.OutputStream: Stream xuất

Ngoài ra còn có các lớp Stream thừa kế từ hai lớp trên nhằm mục đích cung

cấp các tiện ích cho các loại thiết bị vào ra chuyên biệt như: FileInputStream,

FileOutputStream, PipedInputStream, PipedOutputStream, . . .

2.15.1. Lớp java.io.InputStream

Là loại stream cho phép chương trình nhận dữ liệu từ ngoại vi. Có các phương thức

cơ bản sau:

int read() throws IOException: Đọc 1 byte từ Stream

· Return 0-255: Mã ASCII của byte nhận được từ ngoại vi

· -1: Stream đã kết thúc, không còn dữ liệu. Đối với Java, System.in là một

InputStream nối kết với bàn phím được tạo sẵn bởi hệ thống. Chương trình

có thể dùng InputStream này để nhận các ký tự nhập từ bàn phím.

Ví dụ: Hãy lưu chương trình sau vào tập tin InStream1.java

import java.io.*;

public class InStream1 {

public static void main(String args[]) {

InputStream is = System.in; // KeyBoard = System.in

while (true) {

try {

int ch = is.read(); if (ch ==-1 || ch =='q') break; System.out.print((char)ch);

}

Trang 85

catch (IOException ie) { System.out.print("Error: "+ie); }

} } }

Biên dịch và thực thi ta được kết quả sau:

Ví dụ trên chờ nhận các ký tựđược nhập từ bàn phím.

int read(byte b[]) throws IOException: Đọc tất cả các byte hiện có trong Stream

vào mảng b.

· Return 0-255: Số lượng byte đọc được.

· -1 : Stream đã kết thúc, không còn dữ liệu.

int read(byte b[], int offset, int len): Đọc lên byte từ Stream hiện tại, lưu vào trong

mảng b bắt đầu từ vị trí offset

· Return: số lượng byte đọc được.

· -1 : Stream đã kết thúc. Các phương thức trên khi thực thi sẽ bị nghẽn (block)

cho đến khi có dữ liệu hoặc kết trúc Stream hay một ngoại lệ xuất hiện.

· int available(): Trả về số lượng byte hiện có trong Stream mà không làm

nghẽn chương trình.

Ví dụ: Lưu chương trình sau vào tập tin có tên InStream2.java

import java.io.*;

public class InStream2 {

public static void main(String args[]) {

InputStream is = System.in; // KeyBoard = System.in

Trang 86

while (true) {

try {

int num = is.available(); if (num > 0){

byte[] b = new byte[num];

int result = is.read(b);

if (result == -1) break;

String s = new String(b);

System.out.print(s); }

else { System.out.print('.'); } }

catch (IOException ie) { System.out.print("Error: "+ie); }

} } }

Biên dịch và thực thi ta được kết quả sau:

Điểm khác biệt trong ví dụ này là các ký tự ta nhập từ bàn phím sẽ không hiển

thị tức thì trên màn hình. Chúng chỉ hiển thị sau khi chúng ta nhấn phím Enter.

2.15.2. Lớp java.io.OutputStream

Là loại stream cho phép chương trình xuất dữ liệu ra ngoại vi. Có các phương

thức cơ bản sau:

void write(int b) throws IOException

· Viết byte b vào Stream hiện tại,

Trang 87

· Return : void

void write (byte[] b) throws IOException

· Viết tất cả các phần tử của mảng b vào Stream hiện tại

· Return : void

void write (byte[] b, int offset, int len) throws IOException:

· Viết lên phần tử trong mảng b vào Stream hiện tại, bắt đầu từ phần tử có

chỉ số là offset của mảng.

· Return : void

Đối với Java, System.out là một OutputStream nối kết với màn hình được tạo

sẵn bởi hệ thống. Chương trình có thể dùng OutputStream này để gởi các ký tự

ra màn hình.

Ví dụ: Hãy lưu chương trình sau vào tập tin OutStream1.java

import java.io.*;

public class OutStream1 {

public static void main(String args[]) {

OutputStream os = System.out; // Monitor = System.out

try {

String str = "The example of OutputStream";

byte b[] = str.getBytes(); // Đổi chuỗi thành mảng các bytes

os.write(b); } catch (IOException ie) { System.out.print("Error: "+ie); } } }

Biên dịch và thực thi chương trình ta được kết quả sau:

Trang 88

2.15.3. Nhập chuỗi từ một InputStream

InputStream là Stream nh ập gồm chuỗi các bytes. Nó chỉ cung cấp các phương thức

cho việc đọc byte và mảng các bytes. Để có thể đọc được chuỗi từ một InputStream

ta phải sử dụng thêm các lớp sau:

· Lớp java.io.InputStreamReader: Là cầu nối để chuyển InputStream dạng byte

sang InputStream dạng các ký tự (Character).

· Lớp java.io.BufferedReader: Hỗ trợ việc đọc văn bản từ một InputStream

dạng ký tự.

Phương thức String readLine() throws IOException của BufferedReader cho phép

đọc dòng văn bản kế tiếp trong InputStream. Một dòng kết thúc bởi cặp ký tự

‘\r’’\n’ hoặc kết thúc Stream. Return: Một chuỗi ký tự hoặc null. Giả sử is là một

đối tượng thuộc lớp InputStream.

Để đọc chuỗi từ is ta thực hiện các thao tác sau:

1. InputStreamReader isr = new InputStreamReader(is);

2. BufferedReader br = new BufferedReader (isr);

3. String str = br.readLine();

Ví dụ: Đọc chuỗi từ bàn phím, lưu chương trình sau vào tập tin ReadLine.java :

import java.io.*;

public class ReadLine{

public static void main(String args[]) {

InputStreamReader isr = new InputStreamReader(System.in);

BufferedReader br = new BufferedReader(isr);

while (true) {

try { String line = br.readLine();

if (line == null ) break;

System.out.print(line);

} catch (IOException ie) {

System.out.print("Error: "+ie); } } } }

Biên dịch và thực thi ta có kết quả sau:

Trang 89

2.15.4. Xuất chuỗi ra một OutputStream

OutputStream là Stream xuất gồm chuỗi các bytes. Nó chỉ cung cấp các phương

thức cho việc viết byte và mảng các bytes. Để có thể gởi được chuỗi ra một

OutputStream ta phải sử dụng lớp java.io.PrintWriter.

Giả sử: os là một OutputStream, str là chuỗi cần viết vào os. Ta thực hiện các thao

tác sau:

1. PrintWriter pw = new PrintWriter(os);

2. pw.wirte(str);

3. hoặc pw.println(str); // Nếu muốn có ký tự xuống dòng

4. flush() // Đẩy dữ liệu từ buffer ra ngoại vi

Ví dụ: Viết chuỗi ra màn hình Lưu chương trình sau vào tập tin PrintString.java:

import java.io.*;

public class PrintString {

public static void main(String args[]) {

OutputStream os = System.out;

PrintWriter pw = new PrintWriter(os);

pw.write("This is a string \r\n");

pw.println("This is a line");

pw.write("Bye! Bye!"); pw.flush(); } }

Biên dịch và thực thi ta được:

Trang 90

2.16. Lập trình luồng (thread)

Luồng (Thread) là một cách thông dụng để nâng cao năng lực xử lý của các ưng

dụng nhờ vào cơ chế song song. Trong một hệ điều hành cổ điển, đơn vị cơ bản sử

dụng CPU là một quá trình. Mỗi quá trình có một thanh ghi bộ đếm chương trình

(Status Register), ngăn xếp (Stack) và không gian địa chỉ riêng (Address Space).

Ngược lại, trong một hệ điều hành có hỗ trợ tiện ích luồng, đơn vị cơ bản sử dụng

CPU là một luồng. Trong những hệ điều hành này, một quá trình bao gồm một

không gian địa chỉ và nhiều luồng điều khiển. Mỗi luồng có bộ đếm chương trình,

trạng thái thanh ghi và ngăn xếp riêng. Nhưng tất cả các luồng của một quá trình

cùng chia sẻ nhau một không gian địa chỉ. Nhờ đó các luồng có thể sử dụng các

biến toàn cục, chia sẻ các tài nguyên như tập tin, hiệu báo một cách dễ dàng... Cách

thức các luồng chia sẻ CPU cũng giống như cách thức của các quá trình. Một luồng

cũng có những trạng thái: đang chạy (running), sẵn sàng (ready), nghẽn (blocked) và

kết thúc (Dead). Một luồng thì được xem như là một quá trình nhẹ.

Trang 91

Hình 2.7 Các trạng thái của Luồng

Nhờ vào luồng, người ta thiết kế các server có thể đáp ứng nhiều yêu cầu một cách

đồng thời.

Hình 2.8. Sử dụng luồng cho các Server

Trong mô hình này, Server có m ột Luồng phân phát (Dispatcher thread) và nhiều

Luồng thực hiện (Worker thread). Luồng phân phát tiếp nhận các yêu cầu nối kết từ

Trang 92

các Client, rồi chuyển chúng đến các luồng thực hiện còn rảnh để xử lý. Những

luồng thực hiện hoạt động song song nhau và song song với cả luồng phân phát, nhờ

đó, Server có thể phục vụ nhiều Client một cách đồng thời.

2.16.1. Các mức cài đặt luồng

Nhìn từ góc độ hệđiều hành, Luồng có thể được cài đặt ở một trong hai mức:

• Trong không gian người dùng (user space)

• Trong không gian nhân (kernel mode):

2.16.1.1. Tiếp cận luồng ở mức người dùng

Hình 2.9. Kiến trúc luồng cài đặt ở mức người dùng

Không gian người dùng bao gồm một hệ thống runtime mà nó tập hợp những thủ tục

quản lý luồng. Các luồng chạy trong không gian nằm bên trên hệ thống runtime thì

được quản lý bởi hệ thống này. Hệ thống runtime cũng lưu giữ một bảng tin trạng

thái để theo dõi trạng thái hiện hành của mỗi luồng. Tương ứng với mỗi luồng sẽ có

một mục từ trong bảng, bao gồm các thông tin về trạng thái, giá trị thanh ghi, độ ưu

tiên và các thông tin khác về luồng. Tiếp cận này có hai mức định thời biểu

(Scheduling): bộ định thời biểu cho các quá trình nặng và bộ định thời biểu trong hệ

thống runtime. Bộ lập biểu của hệ thống runtime chia thời gian sử dụng CPU được

cấp cho một quá trình thành những khoảng nhỏ hơn để cấp cho các luồng trong quá

trình đó. Như vậy việc kết thúc một luồng thì vượt ra ngoài tầm kiểm soát của kernel

hệ thống.

2.16.1.2. Tiếp cận luồng ở mức nhân hệ điều hành

Trang 93

Hình 2.10. Kiến trúc luồng ở mức hệ thống

Trong tiếp cận này không có hệ thống runtime và các luồng thì được quản lý bởi

kernel của hệ điều hành. Vì vậy, bảng thông tin trạng thái của tất cả các luồng thì

được lưu trữ bởi kernel. Tất cả những lời gọi mà nó làm nghẽn luồng sẽ được bẫy

(TRAP) đến kernel. Khi một luồng bị nghẽn, kernel chọn luồng khác cho thực thi.

Luồng được chọn có thể cùng một quá trình với luồng bị nghẽn hoặc thuộc một quá

trình khác. Vì vậy sự tồn tại của một luồng thì được biết bởi kernel và chỉ có một

mức lập biểu trong hệ thống.

2.16.2. Luồng trong java

Trong Java, luồng là 1 đối tượng thuộc lớp java.lang.Thread. Một chương trình

trong java có thể cài đặt luồng bằng cách tạo ra một lớp con của lớp

java.lang.Thread. Lớp này có 3 phương thức cơ bản để điều khiển luồng là:

· public native synchronized void start()

· public void run()

· public final void stop()

Phương thức start(): Chuẩn bị mọi thứ để thực hiện luồng.

Phương thức run(): Thực hiện công việc thực sự của luồng và sẽ được kích hoạt

một cách tự động bởi phương thức start().

Phương thức stop():Kết thúc luồng.

Luồng sẽ "chết" khi tất cả các công việc trong phương thức run() được thực hiện

hoặc khi phương thức stop() được kích hoạt.

Thí dụ: Sau định nghĩa lớp MyThread là một Thread có:

· Các thuộc tính:

- name: tên của thread

Trang 94

- n: số lần thread xuất hiện ra màn hình

· Các phương thức:

- MyThread(String name, int n): Là phương thức khởi tạo, có nhiệm vụ gán

giá trị cho 2 thuộc tính và gọi phương thức start() để cho thread hoạt động

(start() tự động gọi run())

- run(): In n lần dòng thông báo ra màn hình rồi kết thúc thread.

- main(): Tạo ra 4 thread thuộc lớp MyThread lần lượt có tên là Thread0,

Thread1, Thread2, Thread3. Mỗi thread có 1000 lần xuất hiện ra màn hình.

Lưu chương trình sau vào tập tin MyThread.java:

public class MyThread extends Thread{

String name;

int n;

MyThread(String name, int n){

this.name = name; this.n = n;

System.out.println("Thread "+name+" has been created ....!");

start(); }

public void run(){

for(int i=0; i< n; i++) {

System.out.println("Hello, I'm "+ name);

System.out.println(" I go to bed now, bye bye ... wow ... ");

}

public static void main(String args[]){

int n = 1000; int nt = 4 ;

for (int i=0; i< nt; i++){

MyThread t = new MyThread("Thread"+i,n);

}

} }

Biên dịch và thực thi ta có kết quả sau:

Trang 95

Các Thread in ra màn hình theo thứ tự người lập trình không thể xác định trước

được vì chúng được thực thi song song nhau. Để dừng tạm thời màn hình kết quả

khi chương trình đang thực thi thì chọn chuột vào cửa số DOS mà chương trình

đang chạy; sau đó ta nhấn phín Enter để chương trình tiếp tục.

Ngoài ra, lớp Thread còn có 1 số các phương thức khác :

· public static void sleep(long milliseconds) throws InterruptedException: làm

cho Thread bị nghẽn (Blocked) một khoảng thời gian mili giây xác định.

· public final void suspend(): Chuyển Thread từ trạng thái sẳn sàng sang trạng

thái nghẽn.

· public final void resume(): Chuyển Thread từ trạng thái nghẽn sang trạng thái

sẵn sàng.

· public final void yield(): Chuyển Thread từ trạng thái đang chạy sang trạng

thái sẵn sàng.

2.16.2.1. Độ ưu tiên của luồng

Độ ưu tiên của các luồng xác định mức độ ưu tiên trong việc phân phối CPU giữa

các luồng với nhau. Khi có nhiều luồng đang ở trạng thái "Ready", luồng có độ ưu

Trang 96

tiên cao nhất sẽđược thực thi (chuyển đến trạng thái "running" ). Độ ưu tiên trong

Java được định nghĩa bằng các hằng số nguyên theo thứ tự giảm dần như sau:

· Thread.MAX_PRIORITY

· Thread.NORM_PRIORITY

· Thread.MIN_PRIORITY

Hai phương thức liên quan đến độưu tiên của luồng là:

· setPriority( int x): Đặt độưu tiên của luồng là x

· int getPriority( ): Trả về giá trịưu tiên của luồng

Trong ví dụ này chúng ta tạo ra 12 Thread thuộc lớp MyThread. Một mảng 3 phần

tử tên prio chứa 3 độ ưu tiên từ cao nhất đến thấp nhất. Thread thứ i sẽ có độ ưu tiên

ở vị trí i%3 trong mảng prio. Như vậy các thread 0,3,6,9 có độ ưu tiên cao nhất, sau

đó đến Thread 1,4,7,10 và cuối cùng là các thread 2,5,8,11.

Lưu chương trình sau vào tập tin PriorityThread.java:

public class PriorityThread{

public static void main(String args[]){

int n = 1000; int nt = 12;

int prio[]= {

Thread.MAX_PRIORITY, Thread.NORM_PRIORITY,

Thread.MIN_PRIORITY}; for (int i=0; i< nt; i++){

MyThread t = new MyThread("Thread"+i,n); t.setPriority(prio[i%3]);

} }

Biên dịch và thực thi ta được kết quả như sau:

Trang 97

Các Thread 0,3,9 có độ ưu tiên cao hơn các Thread khác cho nên chúng được

thực thi thường xuyên hơn. Các Thread 2,5,8,11 có độ ưu tiên thấp nhất nên chúng

kết thúc sau cùng.

2.16.3. Đồng bộ hóa giữa các luồng

Trang 98

Tất cả các luồng của một quá trình thì được thực thi song song và độc lập

nhau nhưng lại cùng chia sẻ nhau một không gian địa chỉ của quá trình. Chính vì

vậy có thể dẫn đến khả năng đụng độ trong việc cập nhật các dữ liệu dùng chung

của chương trình (biến, các tập tin được mở) khi một luồng ghi lên một dữ liệu

trong khi một luồng khác đang đọc dữ liệu này. Trong trường hợp đó, cần phải sử

dụng cơ chế đồng bộ hóa của Java. Có nhiều mức đồng bộ hóa như: trên một biến,

trên một câu lệnh, trên một khối lệnh hay trên một phương thức.

2.17. Mô hình ứng dụng truyền thông qua socket và RPC

2.17.1. Mô hình ứng dụng socket

Socket là một giao diện lập trình ứng dụng (API-Application Programming

Interface). Nó được giới thiệu lần đầu tiên trong ấn bản UNIX - BSD 4.2. dưới dạng

các hàm hệ thống theo cú pháp ngôn ngữ C (socket(), bind(), connect(), send(),

receive(), read(), write(), close() ,..).

Ngày nay, Socket được hỗ trợ trong hầu hết các hệ điều hành như MS

Windows, Linux và được sử dụng trong nhiều ngôn ngữ lập trình khác nhau: như C,

C++, Java, Visual Basic, Visual C++, . . .

Socket cho phép thiết lập các kênh giao tiếp mà hai đầu kênh được đánh dấu

bởi hai cổng (port). Thông qua các cổng này một quá trình có thể nhận và gởi dữ

liệu với các quá trình khác.

Trang 99

Hình 2.11. Mô hình socket

2.17.2. Mô hình ứng dụng RPC (Remote Procedure Call)

2.17.2.1. Giới thiệu

Lời gọi thủ tục xa là một cơ chế cho phép một chương trình có thể gọi thực thi

một thủ tục (hay hàm) trên một máy tính khác. Trong chương trình lúc này, tồn tại

hai loại thủ tục: thủ tục cục bộ và thủ tục ở xa.

· Thủ tục cục bộ là thủ tục được định nghĩa, cài đặt và thực thi tại máy của

chương trình.

· Thủ tục ở xa là thủ tục được định nghĩa, cài đặt và thực thi trên một máy tính

khác.

Cú pháp giữa lời gọi thủ tục cục bộ và ở xa thì giống nhau. Tuy nhiên, khi một thủ

tục ở xa được gọi đến, một thành phần của chương trình gọi là Stub sẽ chuyển

hướng để kích hoạt một thủ tục tương ứng nằm trên một máy tính khác với máy của

chương trình gọi. Đối với người lập trình, việc gọi thủ tục xa và thủ tục cục bộ thì

giống nhau về mặt cú pháp. Đây chính là cơ chế cho phép đơn giản hóa việc xây

dựng các ứng dụng ClientServer. Trong hệ thống RPC, Server chính là máy tính

cung cấp các thủ tục ở xa cho phép các chương trình trên các máy tính khác gọi

thực hiện. Client chính là các chương trình có thể gọi các thủ tục ở xa trong quá

Trang 100

trình tính toán của mình. Một Client có thể gọi thủ tục ở xa của nhiều hơn một máy

tính. Như vậy sự thực thi của chương trình Client lúc này không còn gói gọn trên

một máy tính của Client mà nó trải rộng trên nhiều máy tính khác nhau. Đây chính

là mô hình của ứng dụng phân tán (Distributed Application).

2.17.2.2. Kiến trúc của chương trình Client-Server cài đặt theo cơ chế lời gọi

thủ tục xa

Một ứng dụng Client-Server theo cơ chế RPC được xây dựng gồm có sáu phần

như sơ đồ dưới đây:

Hình 2.12 Kiến trúc chương trình kiểu RPC

Phần Client là một quá trình người dùng, nơi khởi tạo một lời gọi thủ tục từ xa.

Mỗi lời gọi thủ tục ở xa trên phần Client sẽ kích hoạt một thủ tục cục bộ tương ứng

nằm trong phần Stub của Client. Phần ClientStub cung cấp một bộ các hàm cục bộ

mà phần Client có thể gọi. Mỗi một hàm của ClientStub đại diện cho một hàm ở xa

được cài đặt và thực thi trên Server. Mỗi khi một hàm nào đó của ClientStub được

gọi bởi Client, ClientStub sẽ đóng gói một thông điệp để mô tả về thủ tục ở xa

Trang 101

tương ứng mà Client muốn thực thi cùng với các tham số nếu có. Sau đó nó sẽ nhờ

hệ thống RPCRuntime cục bộ gởi thông điệp này đến phần Server Stub của Server.

Phần RPCRuntime quản lý việc truyền thông điệp thông qua mạng giữa máy Client

và máy Server. Nó đảm nhận việc truyền lại, báo nhận, chọn đường gói tin và mã

hóa thông tin. RPCRuntime trên máy Client nhận thông điệp yêu cầu từ ClientStub,

gởi nó cho RPCRuntime trên máy Server bằng lệnh send(). Sau đó gọi lệnh wait()

để chờ kết quả trả về từ Server. Khi nhận được thông tiệp từ RPCRuntime của

Client gởi sang, RPCRuntime bên phía server chuyển thông điệp lên phần

ServerStub. ServerStub m ở thông điệp ra xem, xác định hàm ở xa mà Client muốn

thực hiện cùng với các tham số của nó. ServerStub gọi một thủ tục tương ứng nằm

trên phần Server. Khi nhận được yêu cầu của ServerStub, Server cho thực thi thủ tục

được yêu cầu và gởi kết quả thực thi được cho ServerStub.

ServerStub đóng gói kết quả thực trong một gói tin trả lời, chuyển cho phần

RPCRuntime cục bộ để nó gởi sang RPCRuntime của Client RPCRuntime bên phía

Client chuyển gói tin trả lời nhận được cho phần ClientStub. ClientStub mở thông

điệp chứa kết quả thực thi về cho Client tại vị trí phát ra lời gọi thủ tục xa. Trong

các thành phần trên, RPCRuntime được cung cấp bởi hệ thống. ClientStub và

ServerStub có thể tạo ra thủ công (phải lập trình) hay có thể tạo ra bằng các công cụ

cung cấp bởi hệ thống. Cơ chế RPC được hỗ trợ bởi hầu hết các hệ điều hành mạng

cũng như các ngôn ngữ lập trình.

2.17.2.3. Kích hoạt phương thức xa (RMI- Remote Method Invocation )

Giới thiệu RMI là một sự cài đặt cơ chế RPC trong ngôn ngữ lập trình hướng

đối tượng Java. Hệ thống RMI cho phép một đối tượng chạy trên một máy ảo Java

này có thể kích hoạt một phương thức của một đối tượng đang chạy trên một máy ảo

Java khác. Đối tượng có phương thức được gọi từ xa gọi là các đối tượng ở xa

(Remote Object).

Một ứng dụng RMI thường bao gồm 2 phần phân biệt: Môt chương trình Server và

một chương trình Client.

Trang 102

· Chương trình Server tạo một số các Remote Object, tạo các tham chiếu

(reference) đến chúng và chờ những chương trình Client kích hoạt các

phương thức của các Remote Object này.

· Chương trình Client lấy một tham chiếu đến một hoặc nhiều Remote Object

trên Server và kích hoạt các phương thức từ xa thông qua các tham chiếu.

Một chương trình Client có thể kích hoạt các phương thức ở xa trên một hay nhiều

Server. Tức là sự thực thi của chương trình được trải rộng trên nhiều máy tính. Đây

chính là đặc điểm của các ứng dụng phân tán. Nói cách khác, RMI là cơ chế để xây

dựng các ứng dụng phân tán dưới ngôn ngữ Java.

2.17.2.4. Kiến trúc của chương trình

Client-Server theo cơ chế RMI: Kiến trúc một chương trình Client-Server theo

cơ chế RMI được mô tả như hình dưới đây:

Hình 2.13. Kiến trúc chương trình kiểu RMI

Trong đó:

· Server là chương trình cung cấp các đối tượng có thểđược gọi từ xa.

· Client là chương trình có tham chiếu đến các phương thức của các đối tượng

ở xa trên Server.

· Stub chứa các tham chiếu đến các phương thức ở xa trên Server.

Trang 103

· Skeleton đón nhận các tham chiếu từ Stub để kích hoạt phương thức tương

ứng trên Server.

· Remote Reference Layer là hệ thống truyền thông của RMI.

Con đường kích hoạt một phương thức ở xa được mô tả như hình dưới đây:

Hình 2.14 Cơ chế hoạt động của RMI

2.17.2.5. Các cơ chế liên quan trong một ứng dụng đối tượng phân tán

Trong một ứng dụng phân tán cần có các cơ chế sau:

· Cơ chế định vị đối tượng ở xa (Locate remote objects): Cơ chế này xác định

cách thức mà chương trình Client có thể lấy được tham chiếu (Stub) đến các đối

tượng ở xa. Thông thường người ta sử dụng một Dịch vụ danh bạ (Naming

Service) lưu giữ các tham khảo đến các đối tượng cho phép gọi từ xa mà Client

sau đó có thể tìm kiếm.

· Cơ chế giao tiếp với các đối tượng ở xa (Communicate with remote objects): Chi

tiết của cơ chế giao tiếp với các đối tượng ở xa được cài đặt bởi hệ thống RMI.

· Tải các lớp dạng byte codes cho các lớp mà nó được chuyển tải qua lại giữa

Máy ảo (Load class bytecodes for objects that are passed around): Vì RMI cho

phép các chương trình gọi phương thức từ xa trao đổi các đối tượng với các

phương thức ở xa dưới dạng các tham số hay giá trị trả về của phương thức, nên

Trang 104

RMI cần có cơ chế cần thiết để tải mã Byte codes của các đối tượng từ máy ảo

này sang máy ảo khác. Hình dưới đây mô tả một ứng dụng phân tán dưới RMI

sử dụng dịch vụ danh bạ để lấy các tham khảo của các đối tượng ở xa.

Hình 2.15.Ứng dụng phân tán sử dụng dịch vụ danh bạ

Trong đó:

Server đăng ký tên cho đối tượng có thể được gọi từ xa của mình với

Dịch vụ danh bạ (Registry Server).

Client tìm đối tượng ở xa thông qua tên đã được đăng ký trên Registry Server

(looks up) và tiếp đó gọi các phương thức ở xa.

· Hình minh họa cũng cho thấy cách thức mà hệ thống RMI sử dụng một

WebServer sẵn có để truyền tải mã bytecodes của các lớp qua lại giữa Client

và Server.

2.17.2.6. Cơ chế vận hành của của một ứng dụng Client-Server theo kiểu RMI

Tiến trình vận hành của một ứng dụng Client-Server theo kiểu RMI diễn ra như sau:

Bước 1: Server tạo ra các đối tượng cho phép gọi từ xa cùng với các Stub và

Skeleton của chúng.

Bước 2: Server sử dụng lớp Naming để đăng ký tên cho một đối tượng từ xa (1).

Bước 3: Naming đăng ký Stub của đối tượng từ xa với Registry Server (2).

Bước 4: Registry Server sẵn sàng cung cấp tham thảo đến đối tượng từ xa khi có

yêu cầu (3). Client yêu cầu Naming định vị đối tượng xa qua tên đã được đăng ký

(phương thức lookup) với dịch vụ tên (4).

Trang 105

Trang 106

Hình 2.16. Cơ chế vận hành của của một ứng dụng Client-Server theo kiểu RMI

Naming tải Stub của đối tượng xa từ dịch vụ tên mà đối tượng xa đã đăng ký về

Client (5). Cài đặt đối tượng Stub và trả về tham khảo đối tượng xa cho Client (6).

Client thực thi một lời gọi phương thức xa thông qua đối tượng Stub (7).

2.17.2.7. Các lớp hỗ trợ chương trình theo kiểu Client-Server trong Java

Java hỗ trợ các lớp cần thiết để cài đặt các ứng dụng Client-Server theo kiểu RMI

trong các gói: java.rmi. Trong số đó các lớp thường được dùng là:

· java.rmi.Naming

· java.rmi.RMISecurityManager

· java.rmi.RemoteException;

· java.rmi.server.RemoteObject

· java.rmi.server.RemoteServer

· java.rmi. server.UnicastRemoteObject

2.17.2.8. Xây dựng một ứng dụng phân tán với RMI

Trang 107

Xây dựng một ứng dụng phân tán bằng cơ chế RMI gồm các bước sau:

1. Thiết kế và cài đặt các thành phần của ứng dụng.

2. Biên dịch các chương trình nguồn và tạo ra Stub và Skeleton.

3. Tạo các lớp có thể truy xuất từ mạng cần thiết.

4. Khởi tạo ứng dụng

a. Thiết kế và cài đặt các thành phần của ứng dụng.

Đầu tiên phải xác định lớp nào là lớp cục bộ, lớp nào là lớp được gọi từ xa, bao

gồm các bước sau:

• Định nghĩa các giao diện cho các phương thức ở xa (remote interfaces): Một

remote interface mô tả các bởi các Client. Đi cùng với việc định nghĩa Remote

Interface là việc xác định các lớp cục bộ làm tham số hay giá trị trả về của các

phương thức được gọi từ xa.

• Cài đặt các đối tượng từ xa (remote objects): Các Remote Object phải cài đặt cho

một hoặc nhiều Remote Interfaces đã được định nghĩa. Các lớp của Remote Object

class cài đặt cho các phương thức được gọi từ xa đã được khai báo trong Remote

Interface và có thể định nghĩa và cài đặt cho cả các phương thức được sử dụng cục

bộ. Nếu có các lớp làm đối số hay giá trị trả về cho các phương thức được gọi từ xa

thì ta cũng định nghĩa và cài đặt chúng.

• Cài đặt các chương trình Client: Các chương trình Client có sử dụng các Remote

Object có thểđược cài đặt ở bất kỳ thời điểm nào sau khi các Remote Interface đã

được định nghĩa.

b. Biên dịch các tập tin nguồn và tạo Stubs và Skeleton

Giai đoạn này gồm 2 bước: Bước thứ nhất là dùng chương trình biên dịch javac để

biên dịch các tập tin nguồn như các remote interface, các lớp cài đặt cho các remote

interface, lớp server, lớp client và các lớp liên quan khác. Tiếp theo dùng trình biên

dịch rmic để tạo ra stub và skeleton cho các đối tượng từ xa từ các lớp cài đặt cho

các remote interface.

c. Tạo các lớp có thể truy xuất từ mạng

Trang 108

Tạo một tập tin chứa tất cả các file có liên quan như các remote interface stub, các

lớp hỗ trợ mà chúng cần thiết phải tải về Client và làm cho tập tin này có thể truy

cập đến thông qua một Web server.

d. Thực thi ứng dụng

Thực thi ứng dụng bao gồm việc thực thi rmiregistry server, thực thi server, và thực

thi client.

Tóm lại các công việc phải làm là:

· Tạo giao diện (interface) khai báo các phương thức được gọi từ xa của đối

tượng.

· được khai báo.

· Viết chương trình Server.

· Viết chương trình Client.

· Dịch các tập tin nguồn theo dạng RMI để tạo ra các lớp tương ứng và stub

cho client, skeleton cho server.

· Khởi động dịch vụ registry.

· Thực hiện chương trình Server.

· Thực thi chương trình Client.

e. Ví dụ minh họa

Trong ví dụ này định nghĩa một phương thức String sayHello() được gọi từ xa. Mỗi

khi phương thức này được kích hoạt nó sẽ trả về chuỗi "Hello World" cho Client gọi

nó.

Dưới đây là các bước để xây dựng ứng dụng:

Bước 1: Tạo giao diện (interface) khai báo các phương thức được gọi từ xa của đối

tượng.

· Cú pháp tổng quát:

import java.rmi.Remote;

import java.rmi.RemoteException;

public interface InterfaceName extends Remote {

ReturnType remoteMethodOne() throws RemoteException;

ReturnType remoteMethodTwo() throws RemoteException; . . . }

Trang 109

· Định nghĩa remote interface có tên là HelloItf, có phương thức được gọi từ

xa là String sayHello() như sau:

import java.rmi.Remote;

import java.rmi.RemoteException;

public interface HelloItf extends Remote {

String sayHello() throws RemoteException; }

Lưu chương trình này vào tập tin HelloItf.java

Bước 2: Tạo lớp cài đặt (implement) cho giao diện đã được khai báo:

Cú pháp tổng quát:

import java.rmi.server.UnicastRemoteObject;

import java.rmi.RemoteException;

public class RemoteClass extends UnicastRemoteObject implements

InterfaceName { public RemoteClass() throws RemoteException {

super(); ....... // Implement of Method }

public ReturnType remoteMethodOne() throws RemoteException { ....... //

Implement of Method }

public ReturnType remoteMethodTwo() throws RemoteException { ....... //

Definition of Method } }

Định nghĩa lớp cài đặt có tên là Hello cài đặt cho remote interface HelloItf

import java.rmi.server.UnicastRemoteObject;

import java.rmi.RemoteException;

public class Hello extends UnicastRemoteObject implements HelloItf {

public Hello() throws RemoteException { super(); }

public String sayHello() { return "Hello World !"; } }

Lưu chương trình này vào tập tin Hello.java

Bước 3: Viết chương trình Server:

Cú pháp tổng quát:

import java.rmi.Naming;

import java.rmi.RemoteException;

import java.rmi.RMISecurityManager;

Trang 110

public class ServerName {

public static void main(String args[]) {

if (System.getSecurityManager() == null) {// Cài đặt cơ chế bảo mật

System.setSecurityManager(new RMISecurityManager()); }

try { // Tạo các đối tượng từ xa

RemoteClass remoteObject = new RemoteClass(); // Đăng ký tên cho

các đối tượng từ xa

Naming.rebind(“RegistryName", remoteObject); ... }

catch (Exception e) { System.out.println(”Error: . . .” + e);

} } }

Tạo server có tên HelloServer chứa một đối tượng từ xa obj thuộc lớp cài đặt

Hello.

Đăng ký tên cho đối tượng obj là HelloObject

Import java.rmi.Naming;

import java.rmi.RemoteException;

import java.rmi.RMISecurityManager;

public class HelloServer {

public static void main(String args[]) {

if (System.getSecurityManager() == null) {

System.setSecurityManager(new RMISecurityManager());

}

try {

Hello obj = new Hello();

Naming.rebind("HelloObject", obj);

System.out.println("HelloObject is registried");

} catch (Exception e) {

System.out.println("Error: " + e); } } }

Lưu chương trình này vào tập tin HelloServer.java

Bước 4: Viết chương trình Client:

Cú pháp tổng quát:

Trang 111

import java.rmi.Naming;

import java.rmi.RemoteException;

public class Client {

public static void main(String args[]) {

String remoteObjectURL = "rmi://NameServer/RegistryName”;

Interfacename object = null;

try {

o b j e c t = ( In t e r f a c e N a me ) N a mi n g. l o o ku p ( r e m o t e O b j e c t U R L ) ;

object.remoteMethodOne(); ...

} catch (Exception e){ System.out.println(" Error: ”+ e); } } }

Tạo client có tên là HelloClient, tìm đối tượng HelloObject trên rmiregistry

chẳng hạn tại địa chỉ 172.18.211.160.

Gọi phương thức sayHello() và in kết quả trả về ra màn hình.

import java.rmi.Naming;

import java.rmi.RemoteException;

public class HelloClient {

public static void main(String args[]) {

String helloURL = "rmi://172.18.211.160/HelloObject";

HelloItf object = null;

try {

object=(HelloItf)Naming.lookup(helloURL);

String message = object.sayHello(); System.out.println(message);

} catch (Exception e) { System.out.println("Client Error :" + e); } } }

Lưu chương trình vào tập tin HelloClient.java

Bước 5: Dịch các tập tin nguồn theo dạng RMI để tạo ra các lớp tương ứng

và stub cho client, skeleton cho server:

Cú pháp tổng quát:

- javac InterfaceName.java RemoteClass.java Server.java Client.java (T ạo ra

các lớp InterfaceName.class RemoteClass.class Server.class Client.class)

Trang 112

- rmic RemoteClass (Tạo ra các lớp cho Skeleton và Stub:

RemoteClass_Skel.class RemoteClass_Stub.class)

Biên dịch các lớp trong Hello: javac Hello.java HelloItf.java

HelloServer.java HelloClient.java rmic Hello.class

Bước 6: Khởi động dịch vụ rmiregistry o Cú pháp tổng quát: start rmiregistry [port]

Cổng mặc định là 1099.

Khới động dịch vụ rmiregistry trên cổng mặc định:

Khi đó rmiregistry server sẽ chạy trên một cửa sổ mới, giữ nguyên cửa sổ này,

không đóng nó lại.

Trang 113

Bước 7: Thực hiện chương trình Server

Cú pháp tổng quát:

java -Djava.security.policy =UrlOfPolicyFile ServerName

Trong đó UrlOfPolicyFile là địa chỉ theo dạng URL của tập tin mô tả chính

sách về bảo mật mã nguồn của Server (policy file). Nó qui định "ai" (chương trình,

máy tính, quá trình trên) sẽ có quyền download các tập tin của nó trong đó có stub.

Để đơn giản trong phần này ta cho phép tất cả mọi người đều có quyền download

các tập tin của Server. Khi triển khai các ứng dụng thật sự thì phải có các chính sách

bảo mật nghiêm ngặt hơn (Tham khảo tài liệu về Security của Java).

File policy có dạng như sau: grant { // Allow everything for now permission

java.security.AllPermission; };

Lưu nội dung trên vào tập tin có tên policy.java

Thực thi HelloServer với địa tập tin plolicy nằm ở thư mục

D:\progs\policy.java

Trang 114

Bước 8: Thực thi chương trình Client:

Cú pháp tổng quát:

java ClientName

Thực thi HelloClient với địa chỉ của rmiregistry đưa vào trong tham số. Để thực thi

được chương trình HelloClient cần có hai class nằm cùng thư mục với nó là

HelloItf.class và Hello_Stub.class.

Trang 115

Chương 3: LẬP TRÌNH TRUYỀN THÔNG QUA SOCKET

3.1. Đặc điểm của socket

Socket cho phép thiết lập các kênh giao tiếp mà hai đầu kênh được đánh dấu

bởi hai cổng (port). Thông qua các cổng này một quá trình có thể nhận và gởi dữ

liệu với các quá trình khác.

Có hai kiểu socket:

1. Socket kiểu AF_UNIX chỉ cho phép giao tiếp giữa các quá trình trong cùng

một máy tính.

2. Socket kiểu AF_INET cho phép giao tiếp giữa các quá trình trên những máy

tính khác nhau trên mạng.

Số hiệu cổng (Port Number) của socket

Để có thể thực hiện các cuộc giao tiếp, một trong hai quá trình phải công bố số

hiệu cổng của socket mà mình sử dụng. Mỗi cổng giao tiếp thể hiện một địa chỉ xác

định trong hệ thống. Khi quá trình được gán một số hiệu cổng, nó có thể nhận dữ

liệu gởi đến cổng này từ các quá trình khác. Quá trình còn lại cũng được yêu cầu tạo

ra một socket. Ngoài số hiệu cổng, hai bên giao tiếp còn phải biết địa chỉ IP của

nhau. Địa chỉ IP giúp phân biệt máy tính này với máy tính kia trên mạng TCP/IP.

Trong khi số hiệu cổng dùng để phân biệt các quá trình khác nhau trên cùng một

máy tính.

Trang 116

Hình 3.1. Cổng socket

Trong hình trên, địa chỉ của quá trình B1 được xác định bằng 2 thông tin:

(Host B, Port B1): Địa chỉ máy tính có thể là địa chỉ IP dạng 203.162.36.149 hay là

địa chỉ theo dạng tên miền như www.cit.ctu.edu.vn. Số hiệu cổng gán cho Socket

phải duy nhất trên phạm vi máy tính đó, có giá trị trong khoảng từ 0 đến 65535 (16

bits). Trong đó, các cổng từ 1 đến 1023 được gọi là cổng hệ thống được dành riêng

cho các quá trình của hệ thống.

Các cổng mặc định của 1 số dịch vụ mạng thông dụng: Số hiệu cổng của các quá

trình hệ thống

7 Dịch vụ Echo

21 Dịch vụ FTP

23 Dịch vụ Telnet

25 Dịch vụ E-mail (SMTP)

80 Dịch vụ Web (HTTP)

110 Dịch vụ E-mail (POP)

Các chế độ giao tiếp

Trang 117

Xét kiến trúc của hệ thống mạng TCP/IP :

Hình 3.2. Bộ giao thức TCP/IP

Tầng vận chuyển giúp chuyển tiếp các thông điệp giữa các chương trình ứng

dụng với nhau. Nó có thể hoạt động theo hai chế độ:

· Giao tiếp có nối kết, nếu sử dụng giao thức TCP

· Hoặc giao tiếp không nối kết, nếu sử dụng giao thức UDP

Socket là giao diện giữa chương trình ứng dụng với tầng vận chuyển. Nó cho

phép chọn giao thức sử dụng ở tầng vận chuyển là TCP hay UDP cho chương trình

ứng dụng của mình.

Sự khác biệt giữa hai chế độ giao tiếp có nối kết và không nối kết:

Chế độ có nối kết (TCP):

· Tồn tại kênh giao tiếp ảo giữa hai bên giao tiếp

· Dữ liệu được gởi đi theo chế độ bảo đảm: có kiểm tra lỗi. truyền lại gói tin

lỗi hay mất, bảo đảm thứ tự đến của các gói tin . . .

· Dữ liệu chính xác, Tốc độ truyền chậm.

Chế độ không nối kết (UDP) :

· Không tồn tại kênh giao tiếp ảo giữa hai bên giao tiếp

· Dữ liệu được gởi đi theo chế độ không bảo đảm:

Trang 118

· Không kiểm tra lỗi, không phát hiện không truyền lại gói tin bị lỗi hay mất,

không bảo đảm thứ tự đến của các gói tin . . .

· Dữ liệu không chính xác, tốc độ truyền nhanh.

· Thích hợp cho các ứng dụng cần tốc độ, không cần chính xác cao: truyền âm

thanh, hình ảnh . . .

Socket là phương tiện hiệu quả để xây dựng các ứng dụng theo kiến trúc

Client-Server. Các ứng dụng trên mạng Internet như Web, Email, FTP là các ví dụ

điển hình. Phần dưới sẽ trình bày các bước cơ bản trong việc xây dựng các ứng

dụng Client-Server sử dụng Socket làm phương tiện giao tiếp theo cả hai chế độ: Có

nối kết và không nối kết.

3.2. Socket hoạt động ở chế độ có nối kết

3.2.1. Đặc điểm socket hoạt động ở chế độ có nối kết

Các giai đoạn xây dựng ứng dụng như sau :

Giai đoạn 1: Server tạo Socket, gán số hiệu cổng và lắng nghe yêu cầu nối kết:

· socket(): Server yêu cầu tạo một socket để có thể sử dụng các dịch vụ của

tầng vận chuyển.

· bind(): Server yêu cầu gán số hiệu cổng (port) cho socket.

· listen(): Server lắng nghe các yêu cầu nối kết từ các client trên cổng đã được

gán. Server sẵn sàng phục vụ Client.

Giai đoạn 2: Client tạo Socket, yêu cầu thiết lập một nối kết với Server.

Trang 119

· socket(): Client yêu cầu tạo một socket để có thể sử dụng các dịch vụ của

tầng vận chuyển, thông thường hệ thống tự động gán một số hiệu cổng còn

rảnh cho socket của Client.

· connect(): Client gởi yêu cầu nối kết đến server có địa chỉ IP và Port xác

định.

· accept(): Server chấp nhận nối kết của client, khi đó một kênh giao tiếp ảo

được hình thành, Client và server có thể trao đổi thông tin với nhau thông

qua kênh ảo này.

Giai đoạn 3: Trao đổi thông tin giữa Client và Server.

Trang 120

· Sau khi chấp nhận yêu cầu nối kết, thông thường server thực hiện lệnh read()

và nghẽn cho đến khi có thông điệp yêu cầu (Request Message) từ client gởi

đến.

· Server phân tích và thực thi yêu cầu. Kết quả sẽ được gởi về client bằng lệnh

write().

· Sau khi gởi yêu cầu bằng lệnh write(), client chờ nhận thông điệp kết quả

(ReplyMessage) từ server bằng lệnh read(). Trong giai đoạn này, việc trao

đổi thông tin giữa Client và Server phải tuân thủ giao thức của ứng dụng

(Dạng thức và ý nghĩa của các thông điệp, qui tắc bắt tay, đồng bộ hóa,... ).

Thông thường Client sẽ là người gởi yêu cầu đến Server trước.

Nếu phát triển ứng dụng theo các Protocol đã định nghĩa sẵn thì phải tham

khảo và tuân thủ đúng những qui định của giao thức. Mô tả chi tiết của các Protocol

đã được chuẩn hóa trong các tài liệu RFC (Request For Comments). Ngược lại, nếu

muốn phát triển một ứng dụng Client-Server riêng của mình, thì công việc đầu tiên

là phải thực hiện là đi xây dựng Protocol cho ứng dụng.

Giai đoạn 4: Kết thúc phiên làm việc.

· Các câu lệnh read(), write() có thể được thưc hiện nhiều lần (ký hiệu bằng

hình ellipse).

Trang 121

· Kênh ảo sẽ bị xóa khi Server hoặc Client đóng socket bằng lệnh close().

Như vậy toàn bộ tiến trình diễn ra như sau:

Java hỗ trợ lập trình mạng thông qua các lớp trong gói java.net. Một số lớp tiêu

biểu được dùng cho lập trình ứng dụng Client-Server sử dụng socket ở chế độ có nối

kết:

· InetAddress: Lớp này quản lý địa chỉ Internet bao gồm địa chỉ IP và tên máy

tính. Socket: Hỗ trợ các phương thức liên quan đến Socket cho chương trình

Client ở chế độ có nối kết.

· ServerSocket: Hỗ trợ các phương thức liên quan đến Socket cho chương trình

Server ở chế độ có nối kết.

Trang 122

3.2.2. Thí dụ minh họa

3.2.2.1. Xây dựng chương trình Client ở chế độ có nối kết

Các bước tổng quát:

1. Mở một socket nối kết đến server đã biết địa chỉ IP (hay tên miền) và số

hiệu cổng.

2. Lấy InputStream và OutputStream gán với Socket.

3. Tham khảo Protocol của dịch vụ để định dạng đúng dữ liệu trao đổi với

Server.

4. Trao đổi dữ liệu với Server nhờ vào các InputStream và OutputStream.

5. Đóng Socket trước khi kết thúc chương trình.

a. Lớp java.net.Socket

Lớp Socket hỗ trợ các phương thức cần thiết để xây dựng các chương trình

client sử dụng socket ở chế độ có nối kết. Dưới đây là một số phương thức thường

dùng để xây dựng Client:

public Socket(String HostName, int PortNumber) throws IOException

- Phương thức này dùng để nối kết đến một server có tên là HostName, cổng là

PortNumber. Nếu nối kết thành công, một kênh ảo sẽ được hình thành giữa Client

và Server.

- HostName: Địa chỉ IP hoặc tên logic theo dạng tên miền.

- PortNumber: có giả trị từ 0 ..65535

Ví dụ: Mở socket và nối kết đến Web Server: Socket s = new

Socket(“www.ictu.edu.vn”,80);

Hoặc: Socket s = new Socket(“203.162.36.149”,80);

public InputStream getInputStream(): Phương thức này trả về InputStream nối

với Socket. Chương trình Client dùng InputStream này để nhận dữ liệu từ Server gởi

về. Ví dụ: Lấy InputStream của Socket s: InputStream is = s.getInputStream();

public OutputStream getOutputStream(): Phương thức này trả về OutputStream

nối với Socket. Chương trình Client dùng OutputStream này để gởi dữ liệu cho

Server.

Trang 123

Ví dụ: Lấy OutputStream của Socket s: OutputStream os = s.getOutputStream();

public close(): Phương thức này sẽ đóng Socket lại, giải phóng kênh ảo, xóa nối kết

giữa Client và Server.

Ví dụ: Đóng Socket s: s.close();

b. Thí dụ chương trình phía Client

Chương trình TCPEchoClient sẽ nối kết đến EchoServer ở chế độ có nối kết, lần

lượt gởi đến Echo Server 10 ký tự từ ‘0’ đến '9', chờ nhận kết quả trả về và hiển thị

chúng ra màn hình. Lưu chương trình sau vào tập tin TCPEchoClient.java

import java.io.*;

import java.net.Socket;

public class TCPEchoClient{

public static void main(String args[]){

try {

Socket s = new Socket(args[0],7); // Nối kết đến Server

InputStream is = s.getInputStream(); // Lấy InputStream

OutputStream os = s.getOutputStream(); // Lấy OutputStream

for (int i='0'; i<='9';i++){ // Gui ‘0’ ->’9’ den EchoServer

os.write(i); // Gởi 1 ký tự sang Server

int ch = is.read(); // Chờ nhận 1 ký tự từ Server

System.out.print((char)ch); // In ký tự nhận được ra màn hình

}

} //try

catch(IOException ie){

System.out.println("Loi: Khong tao duoc socket"); } //catch

} //main

}

Biên dịch và thực thi chương trình như sau:

Trang 124

Chương trình này nhận một đối số là địa chỉ IP hay tên miền của máy tính mà

ở đó Echo Server đang chạy. Trong hệ thống mạng TCP/IP mỗi máy tính được gán

một địa chỉ IP cục bộ là 127.0.0.1 hay có tên là localhost. Trong ví dụ trên, chương

trình Client nối kết đến Echo Server trên cùng máy với nó.

3.2.2.2. Xây dựng chương trình Server ở chế độ có nối kết

a. Lớp java.net.ServerSocket

Lớp ServerSocket hỗ trợ các phương thức cần thiết để xây dụng các chương

trình Server sử dụng socket ở chế độ có nối kết. Dưới đây là một số phương thức

thường dùng để xây dựng Server:

public ServerSocket(int PortNumber): Phương thức này tạo một Socket với số

hiệu cổng là PortNumber mà sau đó Server sẽ lắng nghe trên cổng này.

Ví dụ: Tạo socket cho Server với số hiệu cổng là 7:

ServerSocket ss = new ServerSocket(7);

public Socket accept(): Phương thức này lắng nghe yêu cầu nối kết của các Client.

Đây là một phương thức hoạt động ở chế độ nghẽn. Nó sẽ bị nghẽn cho đến khi có

một yêu cầu nối kết của client gởi đến. Khi có yêu cầu nối kết của Client gởi đến,

nó sẽ chấp nhận yêu cầu nối kết, trả về một Socket là một đầu của kênh giao tiếp ảo

giữa Server và Client yêu cầu nối kết. Ví dụ: Socket ss chờ nhận yêu cầu nối kết:

Socket s = ss.accept(); Server sau đó sẽ lấy InputStream và OutputStream của

Socket mới s để giao tiếp với Client.

b. Xây dựng chương trình Server phục vụ tuần tự

Một Server có thể được cài đặt để phục vụ các Client theo hai cách: phục vụ tuần tự

hoặc phục vụ song song. Trong chế độ phục vụ tuần tự, tại một thời điểm Server chỉ

Trang 125

chấp nhận một yêu cầu nối kết. Các yêu cầu nối kết của các Client khác đều không

được đáp ứng (đưa vào hàng đợi). Ngược lại trong chế độ phục vụ song song, tại

một thời điểm Server chấp nhận nhiều yêu cầu nối kết và phục vụ nhiều Client cùng

lúc.

Các bước tổng quát của một Server phục vụ tuần tự :

1. Tạo socket và gán số hiệu cổng cho server.

2. Lắng nghe yêu cầu nối kết.

3. Với một yêu cầu nối kết được chấp nhận thực hiện các bước sau:

· Lấy InputStream và OutputStream gắn với Socket của kênh ảo vừa được hình

thành.

· Lặp lại công việc sau: Chờ nhận các yêu cầu (công việc). Phân tích và thực

hiện yêu cầu. Tạo thông điệp trả lời. Gởi thông điệp trả lời về Client. Nếu

không còn yêu cầu hoặc Client kết thúc, đóng Socket và quay lại bước 2.

Trang 126

c. Chương trình STCPEchoServer

STCPEchoServer cài đặt một Echo Server phục vụ tuần tự ở chếđộ có nối kết.

Server lắng nghe trên cổng mặc định số 7.

Lưu chương trình sau vào tập tin STCPEchoServer.java

import java.net.*;

import java.io.*;

public class STCPEchoServer {

public final static int defaultPort = 7;

public static void main(String[] args) {

Trang 127

try {

ServerSocket ss = new ServerSocket(defaultPort);

while (true) {

try {

Socket s = ss.accept();

OutputStream os = s.getOutputStream();

InputStream is = s.getInputStream();

int ch=0; while(true) {

ch = is.read(); if(ch == -1) break;

os.write(ch); }

s.close();

} catch (IOException e) {

System.err.println(" Connection Error: "+e); } } }

catch (IOException e) {

System.err.println(" Server Creation Error:"+e);

} } }

Biên dịch và thực thi chương trình theo cách sau:

Mở một cửa số DOS khác và thực thi chương trình TCPEchoClient ta có kết quả

như sau:

Trang 128

Hai chương trình này có thể nằm trên hai máy khác nhau. Trong trường hợp đó

khi thực hiện chương trình TCPEchoClient phải chú ý nhập đúng địa chỉ IP của máy

tính đang chạy chương trình STCPEchoServer. Xem địa chỉ IP của một máy tính

Windows bằng lệnh ipconfig.

d. Server phục vụ song song

Các bước tổng quát của một Server phục vụ song song Server phục vụ song

song gồm 2 phần thực hiện song song nhau:

Phần 1: Xử lý các yêu cầu nối kết.

Phần 2: Xử lý các thông điệp yêu cầu từ khách hàng. Có cấu trúc như hình sau,

Hình 3. Server ở chế độ song song

Trong đó Phần 1 là (Dispatcher Thread), Phần 2 là các (Worker Thread)

Trang 129

Phần 1: Lặp lại các công việc sau:

· Lắng nghe yêu cầu nối kết của khách hàng.

· Chấp nhận một yêu cầu nối kết.

- Tạo kênh giao tiếp ảo mới với khách hàng.

- Tạo Phần 2 để xử lý các thông điệp yêu cầu của khách hàng.

Phần 2: Lặp lại các công việc sau:

· Chờ nhận thông điệp yêu cầu của khách hàng.

· Phân tích và xử lý yêu cầu.

· Gởi thông điệp trả lời cho khách hàng.

Phần 2 sẽ kết thúc khi kênh ảo bị xóa đi. Với mỗi Client, trên Server sẽ có một Phần

2 để xử lý yêu cầu của khách hàng. Như vậy tại một thời điểm bất kỳ luôn tồn tại 1

Phần 1 và 0 hoặc nhiều Phần 2.

Do Phần 2 thực thi song song với Phần 1 cho nên nó được thiết kế là một Thread.

e. Chương trình PTCPEchoServer

PTCPEchoServer cài đặt một Echo Server phục vụ song song ở chế độ có nối

kết. Server lắng nghe trên cổng mặc định là 7. Chương trình này gồm 2 lớp:

Lớp TCPEchoServer, cài đặt các chức năng của Phần 1 - xử lý các yêu cầu nối kết

của TCPEchoClient.

Lớp RequestProcessing, là một Thread cài đặt các chức năng của Phần 2 - Xử lý các

thông điệp yêu cầu.

Lưu chương trình sau vào tập tin PTCPEchoServer.java

import java.net.*;

import java.io.*;

public class PTCPEchoServer {

public final static int defaultPort = 7; // Cổng mặc định

public static void main(String[] args) {

try {

ServerSocket ss = new ServerSocket(defaultPort); //Tạo socket cho server

while (true) {

try { Socket s = ss.accept(); // Lắng nghe các yêu cầu nối kết

Trang 130

RequestProcessing rp = new RequestProcessing(s); // Tạo phần xử lý

rp.start(); // Khởi động phần xử lý cho Client hiện tại

} catch (IOException e) {

System.out.println("Connection Error: "+e);

} } } catch (IOException e) {

System.err.println("Create Socket Error: "+e); }

} }

class RequestProcessing extends Thread {

Socket channel; //Socket của kênh ảo nối với Client hiện tại

public RequestProcessing(Socket s){

channel = s; // Nhận socket của kênh ảo nối với Client

}

public void run() {

try {

OutputStream os = channel.getOutputStream();

InputStream is = channel.getInputStream();

while (true) { int n = is.read(); // Nhận ký tự từ Client

if (n == -1) break; // Thoát nếu kênh ảo bị xóa

os.write(n); // Gởi ký tự nhận được về Client

} } catch (IOException e) {

System.err.println("Request Processing Error: "+e); }

} }

Biên dịch và thực thi chương trình như sau:

Trang 131

Sau đó mở thêm 2 của sổ DOS khác để thực thi chương trình TCPEchoClient

nối kết tới PTCPEchoServer. Ta sẽ nhận thấy rằng PTCPEchoServer có khả năng

phục vụ đồng thời nhiều Client.

3.3. Socket hoạt động ở chế độ không có nối kết

3.3.1. Đặc điểm socket hoạt động ở chế độ không có nối kết

Xây dựng ứng dụng theo mô hình Client-Server sử dụng Socket ở chế độ

không nối kết (UDP) gồm các giai đoạn sau:

Giai đoạn 1: Server tạo Socket - gán số hiệu cổng.

· socket(): Server yêu cầu tạo một socket để có thể sử dụng các dịch vụ của

tầng vận chuyển.

· bind(): Server yêu cầu gán số hiệu cổng cho socket.

Giai đoạn 2: Client tạo Socket.

Trang 132

Giai đoạn 3: Trao đổi thông tin giữa Client và Server.

Sau khi tạo Socket xong, Client và Server có thể trao đổi thông tin qua lại với

nhau thông qua hai hàm sendto() và recvfrom(). Đơn vị dữ liệu trao đổi giữa Client

và Server là các Datagram Package (Gói tin thư tín). Protocol của ứng dụng phải

định nghĩa khuôn dạng và ý nghĩa của các Datagram Package. Mỗi Datagram

Package có chứa thông tin về địa chỉ người gởi và người nhận (IP, Port).

Một số lớp tiêu biểu trong java.net được dùng cho lập trình ứng dụng Client-Server

sử dụng socket ở chế độ có nối kết:

· DatagramSocket: Hỗ trợ các phương thức liên quan đến Socket ở chế độ

không nối kết cho cả Client và Server.

Trang 133

· DatagramPacket: Lớp cài đặt gói tin dạng thư tín người dùng (Datagram

Packet) trong giao tiếp giữa Client và Server ở chế độ không nối kết.

3.3.2. Thí dụ minh họa

Thí dụ: Xây dựng chương trình Client - Server ở chế độ không nối kết

Khi sử dụng socket, ta có thể chọn giao thức UDP cho lớp vận chuyển. UDP

viết tắt của User Datagram Protocol, cung cấp cơ chế vận chuyển không bảo đảm và

không nối kết trên mạng IP, ngược với giao thức vận chuyển tin cậy, có nối kết

TCP. Cả giao thức TCP và UDP đều phân dữ liệu ra thành các gói tin. Tuy nhiên

TCP có thêm vào những tiêu đề (Header) vào trong gói tin để cho phép truyền lại

những gói tin thất lạc và tập hợp các gói tin lại theo thứ tự đúng đắn. UDP không

cung cấp tính năng này, nếu một gói tin bị thất lạc hoặc bị lỗi, nó sẽ không được

truyền lại, và thứ tự đến đích của các gói tin cũng không giống như thứ tự lúc nó

được gởi đi. Tuy nhiên, về tốc độ, UDP sẽ truyền nhanh gấp 3 lần TCP. Cho nên

chúng thường được dùng trong các ứng dụng đòi hỏi thời gian truyền tải ngắn và

không cần tính chính xác cao, ví dụ truyền âm thanh, hình ảnh . . .

Mô hình client - server sử dụng lớp ServerSocket và Socket ở trên sử dụng

giao thức TCP. Nếu muốn sử dụng mô hình client - server với giao thức UDP, ta sử

dụng hai lớp java.net.DatagramSocket và java.net.DatagramPacket.

DatagramSocket được sử dụng để truyền và nhận các DatagramPacket. Dữ liệu

được truyền đi là một mảng những byte, chúng được gói vào trong lớp

DatagramPacket. Chiều dài của dữ liệu tối đa có thể đưa vào DatagramPacket là

khoảng 60.000 byte (phụ thuộc vào dạng đường truyền). Ngoài ra DatagramPacket

còn chứa địa chỉ IP và cổng của quá trình gởi và nhận dữ liệu. Cổng trong giao thức

TCP và UDP có thể trùng nhau. Trên cùng một máy tính có thể gán cổng 20 cho

socket dùng giao thức TCP và cổng 20 cho socket sử dụng giao thức UDP.

a. Lớp DatagramPacket: Lớp này dùng để đóng gói dữ liệu gởi đi. Dưới đây là các

phương thức thường sử dụng để thao tác trên dữ liệu truyền/nhận qua

DatagramSocket.

public DatagramPacket(byte[] b, int n):

Trang 134

· Là phương thức khởi tạo, cho phép tạo ra một DatagramPacket chứa n bytes

dữ liệu đầu tiên của mảng b. (n phải nhỏ hơn chiều dài của mảng b)

· Phương thức trả về một đối tượng thuộc lớp DatagramePacket.

Ví dụ: Tạo DatagramPacket để nhận dữ liệu:

byte buff[] = new byte[60000]; // Nơi chứa dữ liệu nhận được

DatagramPacket inPacket = new Datagrampacket(buff, buff.lenth);

public DatagramPacket(byte[] b, int n, InternetAddress ia, int port):

· Phương thức này cho phép tạo một DatagramPacket chứa dữ liệu và cả địa

chỉ của máy nhận dữ liệu.

· Phương thức trả về một đối tượng thuộc lớp DatagramePacket

Ví dụ: Tạo DatagramPacket chứa chuỗi "My second UDP Packet", với địa chỉ máy

nhận là www.cit.ctu.edu.vn, cổng của quá trình nhận là 19:

try {// Địa chỉ Internet của máy nhận

InetAddress ia = InetAddess.getByName("www.cit.ctu.edu.vn");

int port = 19; // Cổng của socket nhận

String s = "My second UDP Packet"; // Dữ liệu gởi đi

byte[] b = s.getBytes(); // Đổi chuỗi thành mảng bytes

// Tạo gói tin gởi đi

DatagramPacket outPacket = new DatagramPacket(b, b.length, ia, port);

} catch (UnknownHostException e) { System.err.println(e); }

Các phương thức lấy thông tin trên một DatagramPacket nhận được:

Khi nhận được một DatagramPacket từ một quá trình khác gởi đến, ta có thể lấy

thông tin trên DatagramPacket này bằng các phương thức sau:

· public synchronized() InternetAddress getAddress() : Địa chỉ máy gởi

· public synchronized() int getPort():Cổng của quá trình gởi

· public synchronized() byte[] getData(): Dữ liệu từ gói tin

· public synchronized() int getLength(): Chiều dài của dữ liệu trong gói tin.

Các phương thức đặt thông tin cho gói tin gởi: Trước khi gởi một

DatagramPacket đi, ta có thể đặt thông tin trên DatagramPacket này bằng các

phương thức sau:

Trang 135

public synchronized() void setAddress(IntermetAddress dis): Đặt địa chỉ máy nhận.

public synchronized() void setPort(int port): Đặt cổng quá trình nhận

public synchronized() void setData(byte buffer[]): Đặt dữ liệu gởi

public synchronized() void setLength(int len) : Đặt chiều dài dữ liệu gởi.

b. Lớp DatagramSocket:

Lớp này hỗ trợ các phương thức sau để gởi/nhận các DatagramPacket:

public DatagramSocket() throws SocketException

Tạo Socket kiểu không nối kết cho Client. Hệ thống tự động gán số hiệu cổng chưa

sử dụng cho socket.

Ví dụ: Tạo một socket không nối kết cho Client:

try{ DatagramSocket ds = new DatagramSocket();

} catch(SocketException se) {

System.out.print("Create DatagramSocket Error: "+se); }

public DatagramSocket(int port) throws SocketException: Tạo Socket kiểu

không nối kết cho Server với số hiệu cổng được xác định trong tham số (port).

Ví dụ: Tạo một socket không nối kết cho Server với số hiệu cổng là 7: try{

DatagramSocket dp = new DatagramSocket(7);

} catch(SocketException se) {

System.out.print("Create DatagramSocket Error: "+se); }

public void send(DatagramPacket dp) throws IOException: Dùng để gởi một

DatagramPacket đi. Ví dụ: Gởi chuỗi "My second UDP Packet", cho quá trình ở địa

chỉ www.cit.ctu.edu.vn, cổng nhận là 19:

try { DatagramSocket ds = new DatagramSocket(); //Tạo Socket

//Địa chỉ Internet của máy nhận

InetAddress ia = InetAddess.getByName("www.cit.ctu.edu.vn");

int port = 19; // Cổng của quá trình nhận

String s = "My second UDP Packet"; // Dữ liệu cần gởi

byte[] b = s.getBytes(); // Đổi sang mảng bytes

// Tạo gói tin

DatagramPacket outPacket = new DatagramPacket(b, b.length, ia, port);

Trang 136

ds.send(outPacket); // Gởi gói tin đi

} catch (IOException e) { System.err.println(e); }

public synchronized void receive(Datagrampacket dp) throws IOException: Chờ

nhận một DatagramPacket. Quá trình sẽ bị nghẽn cho đến khi có dữ liệu đến.

Ví dụ:

try { DatagramSocket ds = new DatagramSocket(); //Tạo Socket

byte[] b = new byte[60000]; // Nơi chứa dữ liệu nhận được

DatagramPacket inPacket = new DatagramPacket(b, b.length); // Tạo gói

tin

ds.receive(inPacket); // Chờ nhận gói tin

} catch (IOException e) { System.err.println(e); }

c. Chương trình UDPEchoServer

Chương trình UDPEchoServer cài đặt Echo Server ở chếđộ không nối kết,

cổng mặc định là 7. Chương trình chờ nhận từng gói tin, lấy dữ liệu ra khỏi gói tin

nhận được và gởi ngược dữ liệu đó về Client. Lưu chương trình sau vào tập tin

UDPEchoServer.java:

import java.io.*;

public class UDPEchoServer {

public final static int port = 7; // Cổng mặc định của Server

public static void main(String[] args) {

try { DatagramSocket ds = new DatagramSocket(port); // Tạo Socket với cổng là 7

byte[] buffer = new byte[6000]; // Vùng đệm chứa dữ liệu cho gói tin nhận

while(true) {

// Tạo gói tin nhận

DatagramPacket incoming = new DatagramPacket(buffer,buffer.length);

ds.receive(incoming); // Chờ nhận gói tin gởi đến

// Lấy dữ liệu khỏi gói tin nhận

String theString = new String(incoming.getData(),0,incoming.getLength());

// Tạo gói tin gởi chứa dữ liệu vừa nhận được

Trang 137

DatagramPacket outsending = new DatagramPacket(theString.getBytes(),

incoming.getLength(),incoming.getAddress(), incoming.getPort());

ds.send(outsending);

} } catch (IOException e) { System.err.println(e); } } }

Biên dịch và thực thi chương trình như sau:

d. Chương trình UDPEchoClient

Chương trình này cho phép người sử dụng nhận các chuỗi từ bàn phím, gởi

chuỗi sang EchoServer ở chế độ không nối kết ở cổng số 7, chờ nhận và in dữ liệu

từ Server gởi về ra màn hình. Lưu chương trình sau vào tập tin

UDPEchoClient.java:

import java.io.*;

public class UDPEchoClient extends Object{

public final static int serverPort = 7; // Cổng mặc định của Echo Server public

static void main(String[] args) {

try { if (args.length ==0) { // Kiểm tra tham số, là địa chỉ của Server

System.out.print("Syntax: java UDPClient HostName");

return; }

DatagramSocket ds = new server = InetAddress.getByName(args[0]); // Địa chỉ

Server while(true) {

Trang 138

InputStreamReader isr = new InputStreamReader(System.in);

// Nhập BufferedReader br = new BufferedReader(isr);

// một chuỗi

String theString = br.readLine(); // từ bàn phím

byte[] data = theString.getBytes(); // Đổi chuỗi ra mảng bytes

// Tạo gói tin gởi

DatagramPacket dp = new DatagramPacket(data,data.length,server, serverPort);

ds.send(dp); // Send gói tin sang Echo Server

byte[] buffer = new byte[6000]; // Vùng đệm cho dữ liệu nhận

// Gói tin nhận

DatagramPacket incoming = new DatagramPacket(buffer, buffer.length);

ds.receive(incoming); // Chờ nhận dữ liệu từ EchoServer gởi về

// Đổi dữ liệu nhận được dạng mảng bytes ra chuỗi và in ra màn hình

System.out.println(new String(incoming.getData(), 0, incoming.getLength()));

} } catch (IOException e) { System.err.println(e); } } }

Biên dịch và thực thi chương trình như sau:

UDPEchoClient phải đưa vào đối số là địa chỉ của máy tính đang thực thi

chương trình UDPEchoServer. Trong ví dụ trên, Server và Client cùng chạy trên

một máy nên địa chỉ của UDPEchoServer là localhost (hay 127.0.0.1). Nếu

Trang 139

UDPEchoServer chạy trên máy tính khác thì khi thực thi, ta phải biết được địa chỉ

IP của máy tính đó và cung cấp vào đối số của chương trình. Chẳng hạn, khi

UDPEchoServer đang phục vụ trên máy tính ở địa chỉ 172.18.250.211, ta sẽ thực thi

UDPEchoClient theo cú pháp sau: java UDPEchoClient 172.18.250.211

Trang 140

CHƯƠNG 4: LẬP TRÌNH GIAO TIẾP VỚI CỔNG MÁY TÍNH

4.1. Lập trình cổng LPT

4.1.1. Đặc điểm cổng LPT

Cổng song song LPT trong máy tính có đầu nối lọai D-25 theo chuẩn

Centronics trong hình 8.1.

Hình 4.1 – Các đầu nối D-25 của cổng LPT

Trong hình 8.1, các chân từ :

- Các chân số 2 đến chân số 9 là các chân dữ liệu.

- Các chân 1, 14, 16,17 là các chân dẫn tín hiệu điều khiển

- Các chân 10, 11, 12, 13, 15 là chân trạng thái.

- Các chân từ 18 đến chân 25 là các chân nối đất.

Bảng dưới đây là một sơ đồ các dây của một cổng song song tiêu chuẩn.

Chân Mô tả I/O Chân Mô tả I/O1 -Strobe Out 14 -Auto Feed Out2 +Data Bit 0 Out 15 -Error In3 +Data Bit 1 Out 16 -Initialize Printer Out4 +Data Bit 2 Out 17 -Select Input Out5 +Data Bit 3 Out 18 -Data Bit 0 Return (GND) In6 +Data Bit 4 Out 19 -Data Bit 1 Return (GND) In7 +Data Bit 5 Out 20 -Data Bit 2 Return (GND) In8 +Data Bit 6 Out 21 -Data Bit 3 Return (GND) In

Trang 141

9 +Data Bit 7 Out 22 -Data Bit 4 Return (GND) In10 -Acknowledge In 23 -Data Bit 5 Return (GND) In11 +Busy In 24 -Data Bit 6 Return (GND) In12 +Paper End In 25 -Data Bit 7 Return (GND) In13 +Select In

Bảng 4-1: Bảng mô tả các chân nối của cổng LPT

Trong quá trình khởi động máy tính, ROM BIOS sẽ kiểm tra 3 nhóm cổng

vào/ra lần lượt từ 3BCh đến 378h và 278h để xem liệu có phần cứng cổng song

song nào được lắp trên đó không.

Mỗi cổng LPT có 3 thanh ghi có thể thâm nhập quan 3 địa chỉ cổng vào ra gắn

cho chúng. Mỗi bít trong thanh ghi trạng thái và điều khiển mang các ý nghĩa xác

định khi nhận các giá trị 0 hoặc 1.

Bít Ý nghĩa thanh ghi trạng thái

S7 = 1 nếu máy in không bận

S6 = 0 nếu máy in đã sẵn sang nhận ký tự tiếp theo

S5 = 1 nếu máy in không có giấy

S4 = 1 máy in ở trạng thái on-line

S3 = 0 có lỗi

S2 Không dùng

S1 Không dùng

S0 Không dùng

Bảng 4-2: Ý nghĩa các bit trong thanh ghi trạng thái

Bít Ý nghĩa thanh ghi điều khiển

C7 Không dùng

C6 Không dùng

C5 Không dùng

C4 =1 Chạy ngắt khi ACK=0

C3 = 1 chọn máy in on-line

C2 =0 khởi động máy in

Trang 142

C1 =1 tự động xuống dòng

C0 =1 truyền số liệu tới máy in

Bảng 4-3: Ý nghĩa các bit trong thanh ghi điều khiển

Các thanh ghi này được dùng để gửi số liệu tới máy in, xác định trạng thái máy

in và điều khiển hoạt động của máy in.

- Thanh ghi số liệu được thâm nhập qua địa chỉ cơ sở (vd: 378), hầu hết các máy PC

hiện nay đếu cho phép các thanh ghi này cả viết, cả đọc số liệu theo 2 hướng.

- Thanh ghi trạng thái có địa chỉ bằng địa chỉ cơ sở cộng 1 (vd: 379). Đây là thanh

ghi chỉ đọc. Có thể đọc trược tiếp bằng lệnh vào/ra hoặc dùng ngắt 17, hàm 02h

trong BIOS.

- Thanh ghi điều khiển được thâm nhập thông qua địa chỉ cơ sở công 3 (vd: 37Ah)

và có thể dùng cho cả đọc lẫn viết dữ lieu ra thanh ghi.

Vì tốc độ truyền ký tự của cổng song song nhanh hơn tốc độ in của máy in nên

thông tin ở đây phải có móc nối như hình 8-2. Khởi đâu, PC đặt các số liệu lên bus

sau đó kích hoạt đường xuống mức thấp để thông tin cho máy in biết rằng sốSTB

liệu đã ổn định trên bus. Khi máy in xử lý xong dữ liệu, nó sẽ trả lại tín hiệu ACK

xuống mức thấp để ghi nhận. Máy tính sẽ đợi cho đến khi đường Busy trên máy in

xuống thấp thì sẽ đưa số liệu lên bus.

4.1.2. Các gói và các lớp liên quan đến lập trình cổng LPT

Để lập trình với cổng LPT trên java cần sử dụng gói javax.comm.*, lớp này hỗ

trợ các phương thức và các thuộc tính cho phép truy cập đến các thanh ghi trên

cổng.

4.1.3. Thí dụ minh họa

Thí dụ mở cổng song song:

import java.awt.*;

import java.io.*;

import javax.comm.*;

import java.util.*;

public class CommPortOpen {

Trang 143

/** How long to wait for the open to finish up. */

public static final int TIMEOUTSECONDS = 30;

/** The parent Frame, for the chooser. */

protected Frame parent;

/** The input stream */

protected DataInputStream is;

/** The output stream */

protected PrintStream os;

/** The last line read from the port. */

protected String response;

/** A flag to control debugging output. */

protected boolean debug = true;

/** The chosen Port Identifier */

CommPortIdentifier thePortID;

/** The chosen Port itself */

public static void main(String[] argv) throws IOException, NoSuchPortException,

PortInUseException, UnsupportedCommOperationException {

new CommPortOpen(null).converse();

System.exit(0);

}

/* Constructor */

public CommPortOpen(Frame f)

throws IOException, NoSuchPortException, PortInUseException,

UnsupportedCommOperationException {

// Use the PortChooser from before. Pop up the JDialog.

PortChooser chooser = new PortChooser(null);

String portName = null;

do {

chooser.setVisible(true);

// Dialog done. Get the port name.

Trang 144

portName = chooser.getSelectedName();

if (portName == null)

System.out.println("No port selected. Try again.\n");

} while (portName == null);

// Get the CommPortIdentifier.

thePortID = chooser.getSelectedIdentifier();

// Now actually open the port.

// This form of openPort takes an Application Name and a timeout.

//

System.out.println("Trying to open " + thePortID.getName() + "...");

switch (thePortID.getPortType()) {

case CommPortIdentifier.PORT_PARALLEL:

thePort = thePortID.open("DarwinSys Printing",

TIMEOUTSECONDS * 1000);

ParallelPort pPort = (ParallelPort)thePort;

// Tell API to pick "best available mode" - can fail!

// myPort.setMode(ParallelPort.LPT_MODE_ANY);

// Print what the mode is

int mode = pPort.getMode();

switch (mode) {

case ParallelPort.LPT_MODE_ECP:

System.out.println("Mode is: ECP");

break;

case ParallelPort.LPT_MODE_EPP:

System.out.println("Mode is: EPP");

break;

case ParallelPort.LPT_MODE_NIBBLE:

System.out.println("Mode is: Nibble Mode.");

break;

case ParallelPort.LPT_MODE_PS2:

Trang 145

System.out.println("Mode is: Byte mode.");

break;

case ParallelPort.LPT_MODE_SPP:

System.out.println("Mode is: Compatibility mode.");

break;

// ParallelPort.LPT_MODE_ANY is a "set only" mode;

// tells the API to pick "best mode"; will report the

// actual mode it selected.

default: throw new IllegalStateException ("Parallel mode " + mode + " invalid.");

}

break;

default:// Neither parallel nor serial??

throw new IllegalStateException("Unknown port type " + thePortID);

}

// Get the input and output streams

// Printers can be write-only

try {

is = new DataInputStream(thePort.getInputStream());

} catch (IOException e) {

System.err.println("Can't open input stream: write-only");

is = null;

}

os = new PrintStream(thePort.getOutputStream(), true);

}

/** This method will be overridden by non-trivial subclasses

* to hold a conversation.

*/

protected void converse() throws IOException {

System.out.println("Ready to read and write port.");

// Input/Output code not written -- must subclass.

Trang 146

// Finally, clean up.

if (is != null)

is.close();

os.close();

}}

4.2. Lập trình cổng COM

4.2.1. Đặc điểm cổng COM

Thông tin nối tiếp dùng trong rất nhiều ứng dụng ghép nối với máy vi tính như

chuột, modem, máy vẽ,…Vì dữ liệu được truyền song song trên các bus máy tính

nên để truyền nối tiếp được, bên phát dùng các thanh ghi dịch song song – nối tiếp

để biến đổi các byte song song thành một chuỗi bít nối tiếp nhau cho ra cổng và bên

thu phải dùng các thanh ghi dịch nối tiếp – song song để biến đổi ngược lại.

Thông tin nối tiếp được phân biệt thành 2 loại: truyền nối tiếp đồng bộ và

không đồng bộ. Khi truyền nối tiếp đồng bộ, ngoài đường dây truyền số liệu giữa

hai trạm phát và thu cần có một đường đây điều khiển để truyền tín hiệu nhịp để bên

thu xác định được các thời điểm tại đó số liệu trên đường truyền đã ổn định. Trong

khi đó, truyền nối tiếp không đồng bộ chỉ cần một dây truyền trong đó các thông tin

đồng bộ được truyền ngay cùng với các từ dữ liệu. Đó là bít start chỉ thị sự bắt đầu

của khối dữ liệu được truyền và bít stop báo kết thúc khối dữ liệu được truyền cùng

với một số bit phát hiện và sửa lỗi được ghép cùng các bít số liệu để tạo thành một

khung truyền (frame) hay một USD (serial data unit).

Giữa hai cổng thông tin nối tiếp có thể có các phương thức trao đổi thông tin

như sau:

- Nối đơn công (Simplex Connection): số liệu chỉ được truyền theo một

hướng.

- Bán song công (Half-Duplex): số liệu truyền theo hai hướng , nhưng mỗi

thời điểm chỉ truyền theo một hướng.

- Song công (Full-Duplex): số liệu được truyền thông thời theo cả hai hướng.

Do hạn chế về dải tần của đường truyền nên hầu hết các thiết bị đầu cuối số

liệu DTE (Data Terminal Equipment) muốn thông tin với nhau không thể nối trực

Trang 147

tiếp với môi trường truyền dẫn analog được mà phải thông qua các thiết bị thông tin

số liệu DCE (Data Communication Equipment). Thí dụ, việc thông tin giữa hai máy

tính hoặc máy fax là các DTE qua đường điện thoại công cộng phải được nối qua

hai thiết bị DCE là các Modem.

Các tiêu chuẩn chính cho thông tin số liệu nối tiếp hiện nay được xây dựng bởi

các tổ chức ITU(International Telecommunication Union), EIA (Electronics

Industry Association) và ISO (International Standards Organisation).

Chuẩn RS-232C quy định các ghép nối tiếp giữa một DTE và một DCE với

khoảng cách cực đại là 17m đến 20m và tốc độ truyền số liệu cực đại lên đến 20

kbps.

Tín hiệu theo chuẩn RS-232C là lưỡng cực: mức logic 1 có điện thế dương so

với đất (0V), mức 0 có điện thế dương so với đất.

Với tín hiệu ra: mức lôgic cao có điện thế trong dải từ +5V đến +15V

mức lôgic thấp từ -5V đến -15V

Với tín hiệu vào: mức lôgic cao từ +3V đến +15V

mức lôgic thấp từ -3V đến -15V

Với các máy PC mức điện thế điển hình là 12V.

Dữ liệu được truyền lần lượt theo từng nhóm bít. Mỗi nhóm gọi là một khung

dữ liệu hay một SDU. Một khung truyền bao gồm:

1 bit start luôn ở mức lôgic thấp, điện thế dương.

1 hoặc 1,5 bit hoặc 2 bít stop luôn ở mức logic cáo, diện thế âm.

1 hoặc không có một bít kiểm tra chẵn lẻ,

Hoặc 5,6 hoặc 7 bít số liệu.

Thí dụ, khi truyền đại diện các ký tự (với mã ASCII là 7 bit) được truyền trên đường

dây dẫn lần lượt với khoảng thời gian trễn giữa chúng. Trong khoảng thời gian này

đường truyền ở vào trạng thái MARK (mức logic cao). Hình 8.3 là một thí dụ nhận

được trên trên đường truyền TxD hoặc RxD khi truyền các bit thông tin mà hoăc

ASCII cho 2 chữ ‘A’ với bít chẵn lẻ.

Trang 148

Hình 4.3. Tín hiệu trên đường truyền của các bít biểu diễn 2 kí tự ‘A’

Tốc độ truyền số liệu nôi tiếp được đo bằng số bít truyền trong một giây bps.

Trong các hệ thống truyền số liệu với mã nhị phân tốc độ này trùng với tốc độ baud

là số lần thay đổi tín hiệu trạng thái trong một giây. Hầu hết các máy PC đều có

cổng ghép nối thông tin nối tiếp. Cổng sơ cấp gọi là COM1 (hoặc COM3), cổng thứ

cấp gọi là COM2 (hoặc COM4). Có hai loại đầu cắm cho các tín hiệu này là D-25

(25 chân) và D-9 (9 chân). Các đầu cắm cho các cổng nôi tiếp trên các hộp máy bao

giờ cũng là đầu cắm được (male), đầu cắm nối ra ở các thiết bị ngoại vi là các đầu

cắm cái.

Các trên tín hiệu trên các đầu cắm được nối ra các đường dây để các thiết bị DTE

và DCE thông tin với nhau. Ngoài ra dây GND có điện thế 0V, có thể phân thành 2

nhánh đường dây gồm các đường truyền dữ liệu TxD, RxD và các nhóm các đường

tín hiệu điều khiển (gọi là các tín hiệu móc nối thông tin) gồm các đường còn lại.

4.2.2. Các gói và các lớp liên quan đến lập trình cổng COM

Các lớp hỗ trợ lập trình cho cổng nối tiếp nằm trong gói javax.comm.

4.2.3. Thí dụ minh họa

Thí dụ 1: Để mở cổng nối tiếp để truyền thông dữ liệu cần thực hiện các bước sau:

B1: Nhận về tên cổng sử dụng hàm CommPortIdentifier

B2: Gọi phương thức open() để mở cổng

B3: Thiết lập các tham số cho cổng sử dụng phương thức: setSerialPortParams()

B4: Gọi các phương thức getInputStream và getOutputStream của đối tượng

SerialPort để đọc/ghi trên các stream của cổng.

import java.awt.*;

import java.io.*;

Trang 149

import javax.comm.*;

import java.util.*;

/**

* Open a serial port using Java Communications.

*

*/

public class CommPortOpen {

/** How long to wait for the open to finish up. */

public static final int TIMEOUTSECONDS = 30;

/** The baud rate to use. */

public static final int BAUD = 9600;

/** The parent Frame, for the chooser. */

protected Frame parent;

/** The input stream */

protected DataInputStream is;

/** The output stream */

protected PrintStream os;

/** The last line read from the serial port. */

protected String response;

/** A flag to control debugging output. */

protected boolean debug = true;

/** The chosen Port Identifier */

CommPortIdentifier thePortID;

/** The chosen Port itself */

CommPort thePort;

public static void main(String[] argv) throws IOException,

NoSuchPortException, PortInUseException,

UnsupportedCommOperationException {

new CommPortOpen(null).converse();

System.exit(0);

Trang 150

}

/* Constructor */

public CommPortOpen(Frame f)

throws IOException, NoSuchPortException, PortInUseException,

UnsupportedCommOperationException {

// Use the PortChooser from before. Pop up the JDialog.

PortChooser chooser = new PortChooser(null);

String portName = null;

do {

chooser.setVisible(true);

// Dialog done. Get the port name.

portName = chooser.getSelectedName();

if (portName == null)

System.out.println("No port selected. Try again.\n");

} while (portName == null);

// Get the CommPortIdentifier.

thePortID = chooser.getSelectedIdentifier();

// Now actually open the port.

// This form of openPort takes an Application Name and a timeout.

//

System.out.println("Trying to open " + thePortID.getName() + "...");

switch (thePortID.getPortType()) {

case CommPortIdentifier.PORT_SERIAL:

thePort = thePortID.open("DarwinSys DataComm",

TIMEOUTSECONDS * 1000);

SerialPort myPort = (SerialPort) thePort;

// set up the serial port

myPort.setSerialPortParams(BAUD, SerialPort.DATABITS_8,

SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);

break;

Trang 151

}

break;

default:// Neither parallel nor serial??

throw new IllegalStateException("Unknown port type " + thePortID);

}

// Get the input and output streams

// Printers can be write-only

try {

is = new DataInputStream(thePort.getInputStream());

} catch (IOException e) {

System.err.println("Can't open input stream: write-only");

is = null;

}

os = new PrintStream(thePort.getOutputStream(), true);

}

/** This method will be overridden by non-trivial subclasses

* to hold a conversation.

*/

protected void converse() throws IOException {

System.out.println("Ready to read and write port.");

// Input/Output code not written -- must subclass.

// Finally, clean up.

if (is != null)

is.close();

os.close();

}}

Thí dụ 2: Khởi tạo cổng COM và quay số để thực hiện cuộc gọi

import java.io.*;

import javax.comm.*;

import java.util.*;

Trang 152

/**

* Dial a phone using the Java Communications Package.

*

*/

public class CommPortDial extends CommPortModem {

protected static String number = "000-0000";

public static void main(String[] ap)

throws IOException, NoSuchPortException,PortInUseException,

UnsupportedCommOperationException {

if (ap.length == 1)

number = ap[0];

new CommPortDial().converse( );

System.exit(0);

}

public CommPortDial()throws IOException, NoSuchPortException,

PortInUseException,

UnsupportedCommOperationException {

super(null);

}

protected void converse( ) throws IOException {

String resp; // the modem response.

// Send the reset command

send("ATZ");

expect("OK");

send("ATDT" + number);

expect("OK");

try {

Thread.sleep(5000);

} catch (InterruptedException e) {

// nothing to do

Trang 153

}

is.close( );

os.close( );

}}

Thí dụ 3: Đọc từ cổng nối tiếp: SerialReadByEvents.javaimport java.awt.*; import java.io.*; import javax.comm.*; import java.util.*; public class SerialReadByEvents extends CommPortOpen implements SerialPortEventListener { public static void main(String[] argv) throws IOException, NoSuchPortException, PortInUseException, UnsupportedCommOperationException { new SerialReadByEvents(null).converse( ); } /* Constructor */ public SerialReadByEvents(Frame f) throws IOException, NoSuchPortException, PortInUseException, UnsupportedCommOperationException { super(f); } protected BufferedReader ifile; /** * Hold the conversation. */ protected void converse( ) throws IOException { if (!(thePort instanceof SerialPort)) { System.err.println("But I wanted a SERIAL port!"); System.exit(1); } // Tell the Comm API that we want serial events. ((SerialPort)thePort).notifyOnDataAvailable(true); try { ((SerialPort)thePort).addEventListener(this); } catch (TooManyListenersException ev) { // "CantHappen" error

Trang 154

System.err.println("Too many listeners(!) " + ev); System.exit(0); } // Make a reader for the input file. ifile = new BufferedReader(new InputStreamReader(is)); // } public void serialEvent(SerialPortEvent ev) { String line; try { line = ifile.readLine( ); if (line == null) { System.out.println("EOF on serial port."); System.exit(0); } os.println(line); } catch (IOException ex) { System.err.println("IO Error " + ex); } }

Trang 155

CHƯƠNG 5: THIẾT KẾ HỆ THỐNG TRUYỀN THÔNG

5.1. Điều khiển hệ thống trong java

5.1.1. Các lớp và các gọi hỗ trợ lập trình hệ thống trong java

Để lập trình windows trên java cần sử dụng gói jinvoke.jar, gói này chứa các

lớp cho phép thao tác với hệ điều hành windows như bảng sau:

Lớp J/Invoke Win32 Tên DLL Chức năng

com.jinvoke.win32.Kernel32

Kernel32.dll Base services

com.jinvoke.win32.Gdi32 Gdi32.dll Graphics device interface

com.jinvoke.win32.User32 User32.dll User interface

User interface Advapi32.dll Crypto API, event logging

com.jinvoke.win32.Shell32 Shell32.dll Windows shell API

com.jinvoke.win32.Winmm Winmm.dll Multimedia

com.jinvoke.win32.WinInet WinInet.dll Internet

Gửi các tín hiệu đến tiến trình:

Cài đặt một hàm nhận tín hiệu được gửi đến tiến trình từ nhân:

private void setSignalsHook()

{

// create the signals callback handler for this object

Callback cb = new Callback(this, "signalsHandler");

boolean res = Kernel32.SetConsoleCtrlHandler(cb, true);

// add handler to the list of handlers for the process

if (!res) {

System.out.println("Handler setup failed");

System.exit(0);

}

} // end of setSignalsHook()

Hàm này sẽ nhận được tín hiệu đầu vào như:

CTRL_C_EVENT: khi người dùng nhấn ctrl-c

Trang 156

CTRL_BREAK_EVENT: khi người dùng nhấn ctrl-break

CTRL_CLOSE_EVENT: khi cửa sổ chương trình bị đóng lại

CTRL_LOGOFF_EVENT: khi người dùng log off khỏi hệ thống

CTRL_SHUTDOWN_EVENT: khi hệ thống shutdown

Thí dụ 1: Xuất ra màn hình hộp thoại thông báo dòng chữ: “This

MessageBox is a native Win32 MessageBox”

import com.jinvoke.win32.User32;

import static com.jinvoke.win32.WinConstants.*;

public class HelloWindows2 {

public static void main(String[] args) {

User32.MessageBox(0,

"This MessageBox is a native Win32 MessageBox",

"Hello Windows", MB_ICONINFORMATION|MB_OK);

} }

Thí dụ 2: Lấy thời gian của hệ thống:

import com.jinvoke.JInvoke;

import com.jinvoke.NativeImport;

public class GetSystemTime {

@NativeImport(library="kernel32")

static native void GetSystemTime(SYSTEMTIME pst);

public static void main(String[] args) {

JInvoke.initialize();

SYSTEMTIME systemtime = new SYSTEMTIME();

GetSystemTime(systemtime);

System.out.println(

"\tyear : " + systemtime.wYear +

"\n\tmonth : " + systemtime.wMonth +

"\n\tDayOfWeek : " + systemtime.wDayOfWeek +

"\n\tDay : " + systemtime.wDay +

"\n\tHour : " + systemtime.wHour+

Trang 157

"\n\tMinute : " + systemtime.wMinute+

"\n\tSecond : " + systemtime.wSecond+

"\n\tMillisecond : " + systemtime.wMilliseconds);

} }

5.1.2. Phát hiện vị trí của chuột

Thí dụ chương trình PollingWin.java:

// globals

private int hwnd; // handle for the window

private Rectangle winRect; // same size as the window

public void run()

{

Point pos = new Point(); // a JInvoke Point object;

while (true) {

User32.GetCursorPos(pos);

System.out.println("Screen pos: (" + pos.x + ", " + pos.y + ")");

User32.ScreenToClient(hwnd, pos);

System.out.println("Window pos: (" + pos.x + ", " + pos.y +

"); inside: " + winRect.contains(pos.x, pos.y));

System.out.println("Mouse state [L,M,R]: [" +

isPressed(WinConstants.VK_LBUTTON) + "," +

isPressed(WinConstants.VK_MBUTTON) + "," +

isPressed(WinConstants.VK_RBUTTON) + "]");

int ch = getLetter();

if (ch != 0)

System.out.println("Letter: " + (char)ch);

if (isFinished())

System.exit(0);

try {

Trang 158

Thread.sleep(200);

} catch(InterruptedException e) {}

}

} // end of run()

5.1.4. Phát hiện sự kiện chuột hoặc phím được nhấn

private boolean isPressed(int key)

// is key (or mouse button) pressed down?

{ return ((User32.GetAsyncKeyState(key) & 0x8000) == 0x8000); }

Để nhận về ký tự hoặc sự kiện chuột được nhấn:

private int getLetter()

// return a letter (in its ASCII form), or 0

{

boolean isShifted = isShifted();

for (int key = 65; key <= 90; key++) { // ASCII range of A-Z

if (isPressed(key)) {

if (isShifted)

return key;

else // not shifted

return (key+32); // convert key to ASCII range a-z

}

}

return 0;

} // end of getLetter()

private boolean isShifted()

// check if the left or right hand shift key has been pressed

{

return (isPressed(WinConstants.VK_SHIFT) ||

isPressed(WinConstants.VK_RSHIFT));

}

Kết thúc quá trình phát hiện sự kiện chuột và bàn phím

Trang 159

private boolean isFinished()

// check for ctrl-c, ESC, and END to indicate things are finished

{

if (isPressed(WinConstants.VK_CONTROL) && isPressed(67)) {

System.out.println("ctrl-c"); // 67 == C key

return true;

}

if(isPressed(WinConstants.VK_ESCAPE)) {

System.out.println("ESC");

return true;

}

if(isPressed(WinConstants.VK_END)) {

System.out.println("END");

return true;

}

return false; // not finished

} // end of isFinished()

5.2. Mô hình ứng dụng truyền thông giữa PC-PC

Mỗi PC trang bị thêm các thiết bị truyền thông và được kết nối trực tiếp vào

mạng Internet thông qua giao diện NIC với mạng LAN hoặc thông qua Modem /

cable modem khi kết nối qua ISP (Internet Sevice Provider).

5.3. Mô hình ứng dụng truyền thông giữa PC – Phone

Người dùng PC hình thành cuộc gọi với người dùng mạng thoại PSTN thông

thường. Cấu trúc này là đường dẫn tới việc kết hợp giữa mạng IP và PSTN.

5.4. Mô hình ứng dụng truyền thông giữa PC – PSTN - Phone

Là mô hình mở rộng của PC – Phone, sử dụng Internet làm cơ sở để tính cước

phí điện thoại cho người sử dụng mạng PSTN. Mô hình này sử dụng một mã số đặc

biệt là giá trị cổng kết nối giữa PSTN và mạng Internet rồi mới nhấn số điện thoại

cần gặp. Mọi quá trình lấy mẫu và mã hoá đều diễn ra ở gateway.

5.5. Thí dụ minh họa

Trang 160

Chương trình gửi SMS giữa máy tính với điện thoại:Thiết lập tham số cho cổng nối tiếp:import javax.comm.*;public class SerialParameters { private String portName; private int baudRate; private int flowControlIn; private int flowControlOut; private int databits; private int stopbits; private int parity; public SerialParameters () { this("", 9600, SerialPort.FLOWCONTROL_NONE, SerialPort.FLOWCONTROL_NONE, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE ); } public SerialParameters(String portName, int baudRate, int flowControlIn, int flowControlOut, int databits, int stopbits, int parity) {

this.portName = portName; this.baudRate = baudRate; this.flowControlIn = flowControlIn; this.flowControlOut = flowControlOut; this.databits = databits; this.stopbits = stopbits; this.parity = parity; } public void setPortName(String portName) {

Trang 161

this.portName = portName; } public String getPortName() { return portName; } public void setBaudRate(int baudRate) { this.baudRate = baudRate; } public void setBaudRate(String baudRate) { this.baudRate = Integer.parseInt(baudRate); } public int getBaudRate() { return baudRate; } public String getBaudRateString() { return Integer.toString(baudRate); } public void setFlowControlIn(int flowControlIn) { this.flowControlIn = flowControlIn; } public void setFlowControlIn(String flowControlIn) { this.flowControlIn = stringToFlow(flowControlIn); } public int getFlowControlIn() { return flowControlIn; } public String getFlowControlInString() { return flowToString(flowControlIn); } public void setFlowControlOut(int flowControlOut) { this.flowControlOut = flowControlOut; } public void setFlowControlOut(String flowControlOut) { this.flowControlOut = stringToFlow(flowControlOut); } public int getFlowControlOut() { return flowControlOut;

Trang 162

} public String getFlowControlOutString() { return flowToString(flowControlOut); } public void setDatabits(int databits) { this.databits = databits; } public void setDatabits(String databits) { if (databits.equals("5")) { this.databits = SerialPort.DATABITS_5; } if (databits.equals("6")) { this.databits = SerialPort.DATABITS_6; } if (databits.equals("7")) { this.databits = SerialPort.DATABITS_7; } if (databits.equals("8")) { this.databits = SerialPort.DATABITS_8; } } public int getDatabits() { return databits; } public String getDatabitsString() { switch(databits) { case SerialPort.DATABITS_5: return "5"; case SerialPort.DATABITS_6: return "6"; case SerialPort.DATABITS_7: return "7"; case SerialPort.DATABITS_8: return "8"; default: return "8"; }

Trang 163

} public void setStopbits(int stopbits) { this.stopbits = stopbits; } public void setStopbits(String stopbits) { if (stopbits.equals("1")) { this.stopbits = SerialPort.STOPBITS_1; } if (stopbits.equals("1.5")) { this.stopbits = SerialPort.STOPBITS_1_5; } if (stopbits.equals("2")) { this.stopbits = SerialPort.STOPBITS_2; } } public int getStopbits() { return stopbits; } public String getStopbitsString() { switch(stopbits) { case SerialPort.STOPBITS_1: return "1"; case SerialPort.STOPBITS_1_5: return "1.5"; case SerialPort.STOPBITS_2: return "2"; default: return "1"; } } public void setParity(int parity) { this.parity = parity; } public void setParity(String parity) { if (parity.equals("None")) { this.parity = SerialPort.PARITY_NONE; }

Trang 164

if (parity.equals("Even")) { this.parity = SerialPort.PARITY_EVEN; } if (parity.equals("Odd")) { this.parity = SerialPort.PARITY_ODD; } } public int getParity() { return parity; } public String getParityString() { switch(parity) { case SerialPort.PARITY_NONE: return "None"; case SerialPort.PARITY_EVEN: return "Even"; case SerialPort.PARITY_ODD: return "Odd"; default: return "None"; } } private int stringToFlow(String flowControl) { if (flowControl.equals("None")) { return SerialPort.FLOWCONTROL_NONE; } if (flowControl.equals("Xon/Xoff Out")) { return SerialPort.FLOWCONTROL_XONXOFF_OUT; } if (flowControl.equals("Xon/Xoff In")) { return SerialPort.FLOWCONTROL_XONXOFF_IN; } if (flowControl.equals("RTS/CTS In")) { return SerialPort.FLOWCONTROL_RTSCTS_IN; } if (flowControl.equals("RTS/CTS Out")) { return SerialPort.FLOWCONTROL_RTSCTS_OUT;

Trang 165

} return SerialPort.FLOWCONTROL_NONE; } String flowToString(int flowControl) { switch(flowControl) { case SerialPort.FLOWCONTROL_NONE: return "None"; case SerialPort.FLOWCONTROL_XONXOFF_OUT: return "Xon/Xoff Out"; case SerialPort.FLOWCONTROL_XONXOFF_IN: return "Xon/Xoff In"; case SerialPort.FLOWCONTROL_RTSCTS_IN: return "RTS/CTS In"; case SerialPort.FLOWCONTROL_RTSCTS_OUT: return "RTS/CTS Out"; default: return "None"; } }}Thực hiện kết nối tới cổng nối tiếp:import javax.comm.*;import java.io.*;import java.awt.TextArea;import java.awt.event.*;import java.util.TooManyListenersException;public class SerialConnection implements SerialPortEventListener, CommPortOwnershipListener { private SerialParameters parameters; private OutputStream os; private InputStream is; private KeyHandler keyHandler;

private CommPortIdentifier portId; private SerialPort sPort;

private boolean open;

private String receptionString="";

Trang 166

public String getIncommingString(){ byte[] bVal= receptionString.getBytes(); receptionString=""; return new String (bVal); } public SerialConnection(SerialParameters parameters) { this.parameters = parameters; open = false; } public void openConnection() throws SerialConnectionException {

// System.out.println("OK 0 "); // Obtain a CommPortIdentifier object for the port you want to open. try { // System.out.println(parameters.getPortName()); portId = CommPortIdentifier.getPortIdentifier(parameters.getPortName()); } catch (NoSuchPortException e) { // System.out.println("Yes the problem is here 1 "); e.printStackTrace(); // throw new SerialConnectionException(e.getMessage()); }catch(Exception e) { // System.out.println("ErrorErrorErrorError"); e.printStackTrace(); } //System.out.println(portId); //System.out.println("OK 1 "); // Open the port represented by the CommPortIdentifier object. Give // the open call a relatively long timeout of 30 seconds to allow // a different application to reliquish the port if the user // wants to. try { sPort = (SerialPort)portId.open("SMSConnector", 30000); } catch (PortInUseException e) {

Trang 167

throw new SerialConnectionException(e.getMessage()); } //System.out.println("OK 2 "); sPort.sendBreak(1000);

// Set the parameters of the connection. If they won't set, close the // port before throwing an exception. try { setConnectionParameters(); } catch (SerialConnectionException e) { sPort.close(); throw e; } // System.out.println("OK 3 "); // Open the input and output streams for the connection. If they won't // open, close the port before throwing an exception. try { os = sPort.getOutputStream(); is = sPort.getInputStream(); } catch (IOException e) { sPort.close(); throw new SerialConnectionException("Error opening i/o streams"); }//System.out.println("OK 4 "); try { sPort.addEventListener(this); } catch (TooManyListenersException e) { sPort.close(); throw new SerialConnectionException("too many listeners added"); }//System.out.println("OK 5 "); // Set notifyOnDataAvailable to true to allow event driven input. sPort.notifyOnDataAvailable(true); // Set notifyOnBreakInterrup to allow event driven break handling. sPort.notifyOnBreakInterrupt(true); // Set receive timeout to allow breaking out of polling loop during // input handling.

Trang 168

try { sPort.enableReceiveTimeout(30); } catch (UnsupportedCommOperationException e) { }//System.out.println("OK 6 "); // Add ownership listener to allow ownership event handling. portId.addPortOwnershipListener(this);

open = true; }

public void setConnectionParameters() throws SerialConnectionException { // Save state of parameters before trying a set. int oldBaudRate = sPort.getBaudRate(); int oldDatabits = sPort.getDataBits(); int oldStopbits = sPort.getStopBits(); int oldParity = sPort.getParity(); int oldFlowControl = sPort.getFlowControlMode(); // Set connection parameters, if set fails return parameters object // to original state. try { sPort.setSerialPortParams(parameters.getBaudRate(), parameters.getDatabits(), parameters.getStopbits(), parameters.getParity()); } catch (UnsupportedCommOperationException e) { parameters.setBaudRate(oldBaudRate); parameters.setDatabits(oldDatabits); parameters.setStopbits(oldStopbits); parameters.setParity(oldParity); throw new SerialConnectionException("Unsupported parameter"); } // Set flow control. try { sPort.setFlowControlMode(parameters.getFlowControlIn() | parameters.getFlowControlOut()); } catch (UnsupportedCommOperationException e) {

Trang 169

throw new SerialConnectionException("Unsupported flow control"); } } public void closeConnection() { // If port is alread closed just return. if (!open) { return; } // Remove the key listener.// messageAreaOut.removeKeyListener(keyHandler); // Check to make sure sPort has reference to avoid a NPE. if (sPort != null) { try { // close the i/o streams. os.close(); is.close(); } catch (IOException e) { System.err.println(e); } // Close the port. sPort.close(); // Remove the ownership listener. portId.removePortOwnershipListener(this); } open = false; } public void sendBreak() { sPort.sendBreak(1000); } public boolean isOpen() { return open; } public void serialEvent(SerialPortEvent e) { // Create a StringBuffer and int to receive input data. StringBuffer inputBuffer = new StringBuffer(); int newData = 0; // Determine type of event.

Trang 170

switch (e.getEventType()) { // Read data until -1 is returned. If \r is received substitute // \n for correct newline handling. case SerialPortEvent.DATA_AVAILABLE: while (newData != -1) { try { newData = is.read(); if (newData == -1) { break; } if ('\r' == (char)newData) { inputBuffer.append('\n'); } else { inputBuffer.append((char)newData); } } catch (IOException ex) { System.err.println(ex); return; } } // Append received data to messageAreaIn. receptionString=receptionString+ (new String(inputBuffer)); //System.out.print("<-"+receptionString); break; // If break event append BREAK RECEIVED message. case SerialPortEvent.BI: receptionString=receptionString+("\n--- BREAK RECEIVED ---\n"); } } public void ownershipChange(int type) { } class KeyHandler extends KeyAdapter { OutputStream os;

/** Creates the KeyHandler. @param os The OutputStream for the port.

Trang 171

*/ public KeyHandler(OutputStream os) { super(); this.os = os; } /** Handles the KeyEvent. Gets the <code>char</char> generated by the <code>KeyEvent</code>, converts it to an <code>int</code>, writes it to the <code> OutputStream</code> for the port. */ public void keyTyped(KeyEvent evt) { char newCharacter = evt.getKeyChar(); if ((int)newCharacter==10) newCharacter = '\r'; System.out.println ((int)newCharacter); try { os.write((int)newCharacter); } catch (IOException e) { System.err.println("OutputStream write error: " + e); } } } public void send(String message) { byte[] theBytes= (message+"\n").getBytes(); for (int i=0; i<theBytes.length;i++){

char newCharacter = (char)theBytes[i]; if ((int)newCharacter==10) newCharacter = '\r'; try { os.write((int)newCharacter); } catch (IOException e) { System.err.println("OutputStream write error: " + e); } } //System.out.println (">'" +message +"' sent");Xử lý ngoại lệ trên cổng nối tiếp:public class SerialConnectionException extends Exception {

Trang 172

public SerialConnectionException(String str) { super(str); } public SerialConnectionException() { super(); }}Tện Sender.java thực hiện gửi tin nhắn tới số điện thoại:import java.util.Date;public class Sender implements Runnable { private static final long STANDARD=500; private static final long LONG=2000; private static final long VERYLONG=20000; SerialConnection mySerial =null; static final private char cntrlZ=(char)26; String in, out; Thread aThread=null; private long delay=STANDARD; String recipient=null; String message=null; private String csca="+6596845999"; // the message center private SerialParameters defaultParameters= new SerialParameters("COM2",9600,0,0,8,1,0); public int step; public int status=-1; public long messageNo=-1; public Sender(String recipient, String message){ this.recipient=recipient; this.message=message; } public int send () throws Exception{ SerialParameters params = defaultParameters; mySerial =new SerialConnection (params); mySerial.openConnection(); aThread=new Thread(this); aThread.start() ; //log("start");

Trang 173

return 0; } public void run(){ boolean timeOut=false; long startTime=(new Date()).getTime(); while ((step <7) && (!timeOut)){// log(""+((new Date()).getTime() - startTime); //check where we are in specified delay timeOut=((new Date()).getTime() - startTime)>delay; //if atz does not work, type to send cntrlZ and retry, in case a message was stuck if (timeOut && (step==1)) { step=-1; mySerial.send( ""+cntrlZ); } //read incoming string String result= mySerial.getIncommingString() ;// log ("<- "+result+"\n--------"); int expectedResult=-1; try{ //log ("Step:"+step); switch (step){ case 0: mySerial.send("atz"); delay=LONG; startTime=(new Date()).getTime(); break; case 1: delay=STANDARD; mySerial.send("ath0"); startTime=(new Date()).getTime(); break; case 2: expectedResult=result.indexOf("OK"); //log ("received ok ="+expectedResult); if (expectedResult>-1){ mySerial.send("at+cmgf=1"); startTime=(new Date()).getTime();

Trang 174

}else{ step=step-1; } break; case 3: expectedResult=result.indexOf("OK");

// log ("received ok ="+expectedResult); if (expectedResult>-1){ mySerial.send("at+csca=\""+csca+"\""); startTime=(new Date()).getTime(); }else{ step=step-1; } break; case 4: expectedResult=result.indexOf("OK"); // log ("received ok ="+expectedResult); if (expectedResult>-1){ mySerial.send("at+cmgs=\""+recipient+"\""); startTime=(new Date()).getTime(); }else{ step=step-1; } break; case 5: expectedResult=result.indexOf(">"); // log ("received ok ="+expectedResult); if (expectedResult>-1){ mySerial.send(message+cntrlZ); startTime=(new Date()).getTime(); }else{ step=step-1; } delay=VERYLONG;//waitning for message ack break; case 6:

Trang 175

expectedResult=result.indexOf("OK"); //read message number if (expectedResult>-1){ int n=result.indexOf("CMGS:"); result=result.substring(n+5); n=result.indexOf("\n"); status=0; messageNo=Long.parseLong(result.substring(0,n).trim() ); log ("sent message no:"+messageNo); }else{ step=step-1; } break; } step=step+1; aThread.sleep(100); }catch (Exception e){ e.printStackTrace(); } } mySerial.closeConnection() ; //if timed out set status if (timeOut ) { status=-2; log("*** time out at step "+step+"***"); } } private void log(String s){ System.out.println (new java.util.Date()+":"+this.getClass().getName()+":"+s); }}Thực hiện gửi tin nhắn:public class SMSClient implements Runnable{ public final static int SYNCHRONOUS=0; public final static int ASYNCHRONOUS=1; private Thread myThread=null; private int mode=-1;

Trang 176

private String recipient=null; private String message=null; public int status=-1; public long messageNo=-1; public SMSClient(int mode) { this.mode=mode; } public int sendMessage (String recipient, String message){ this.recipient=recipient; this.message=message; //System.out.println("recipient: " + recipient + " message: " + message); myThread = new Thread(this); myThread.start();// run(); return status; } public void run(){ Sender aSender = new Sender(recipient,message); try{ //send message aSender.send (); // System.out.println("sending ... "); //in SYNCHRONOUS mode wait for return : 0 for OK, -2 for timeout, -1 for othererrors if (mode==SYNCHRONOUS) { while (aSender.status == -1){ myThread.sleep (1000); } } if (aSender.status == 0) messageNo=aSender.messageNo ; }catch (Exception e){ e.printStackTrace(); } this.status=aSender.status ; aSender=null; }}