CƠ CHẾ TRUYỀN NHẬN DỮ LIỆU

Một phần của tài liệu Thiết kế chương trình truyền tiếng nói qua mạng LAN thông qua sự trợgiúp của công cụ SDK (Trang 45 - 50)

TÌM HIỂU HỖ TRỢ CỦA WINDOWS SDK TRONG XỬ LÝ VÀ TRUYỀN NHẬN ÂM THANH

IV.2.3 CƠ CHẾ TRUYỀN NHẬN DỮ LIỆU

Khi viết một ứng dụng trên môi trường Windows, chúng ta phải lưu ý đến đặc điểm của môi trường Windows là môi trường có kiến trúc message-driven. Windows được xem là một môi trường có kiến trúc message-driven hay event-driven vì không một chương trình nào trên windows có thể thực thi nếu không có một Thông báo hay một sự kiện kích khởi nó. Trong môi trường Windows luôn tồn tại một vòng lặp message loop. Vòng message loop này sẽ truy xuất các Thông báo từ các hàng chờ của các chương trình và tùy theo loại Thông báo hay sự kiện, nó cho phép window procedure tương ứng thực thi. Vì vậy trên môi trường Windows có thể tồn tại nhiều ứng dụng cùng một lúc mỗi ứng dụng có một hàng chờ Thông báo riêng. Khi có một sự kiện xảy ra, hệ thống sẽ xác định xem sự kiện đó tuơng ứng với ứng dụng nào và chuyển Thông báo đến hàng chờ của ứng dụng tương ứng đó. Tùy theo loại Thông báo mà ứng dụng sẽ gọi chương trình tương ứng thực thi.

Môi trường windows 16 bits là môi trường nonpreemptive, có nghĩa là khi một ứng dụng đang xử lý một Thông báo thì không một ứng dụng nào có thể thực thi được. Phải chờ cho đến khi procedure của ứng dụng tiến hành xong công việc và trả về thì lúc đó procedure tương ứng với Thông báo tiếp theo trong hàng chờ mới được thực thi. Trong khi đó các môi trường Win32 như Windows98, WindowsNT lại thực thi theo cơ chế preemptive. Trong môi trường này, việc procedure nào được thực thi là do hệ thống quyết định. Thật ra, trong môi trường Win32, hệ thống định thời cho các

thread thực thi. Thread chính là đoạn mã thực thi của một chương trình nên các chương trình đều có cơ hội thực thi.

Khi winsock được thiết kế lần đầu tiên, các mô hình thiết kế được làm cho phù hợp với cơ chế “ message-driven” và “ nonpreemptive” của Windows 16bits. Một số hàm socket nguyên thủy khi thực thi cần một khoảng thời gian tương đối. Khi hàm thực thi rơi vào tình trạng này, nó được gọi là bị tắc nghẽn. Khi một hàm bị tắc nghẽn, nó sẽ ngăn trở việc thực thi của các hàm khác trong hệ thống. Trong hệ thống UNIX, môi trường mà socket được thiết kế đầu tiên, các hàm blocking này không gây trở ngại cho hệ thống vì hệ thống sẽ chiếm giữ các quá trình bị blocking và cho phép các quá trình khác thực thi.

Trong khi đó, hệ thống Windows 16 bits không có khả năng chiếm giữ các quá trình blocking. Dẫn đến việc hệ thống không tiếp tục thực thi được vì các quá trình khác không có cơ hội thực thi. Hệ thống phải chờ cho đến khi quá trình blocking hoàn tất công việc thì mới tiếp tục thực thi được. Khi thiết kế winsock, các nhà thiết kế đã tính đến khả năng này. Vì vậy họ có một giải pháp là đưa một đoạn mã đặc biệt vào hàm blocking để cho phép các quá trình khác kiểm tra được hàng chờ Thông báo của mình. Tuy nhiên đây không phải là một giải thuật hiệu quả.

Trong hệ thống socket của Berkeley các nhà nghiên cứu cũng đã lưu ý đến vấn đề này khi thiết kế, và họ đã thiết kế các hàm nonblocking bên cạnh các hàm blocking.

Chúng ta xét một ví dụ là hàm send() của socket. Khi hoạt động ở chế độ blocking, hàm send() sẽ gửi dữ liệu đi, hàm sẽ bị tắc nghẽn và nó chỉ trả về khi hoàn tất việc truyền dữ liệu, tức là dữ liệu đã được nhận hoàn toàn. Còn nếu socket được tạo ra ở cơ chế bất đồng bộ, hàm send() sẽ hoạt động ở chế độ non-blocking. Hàm send() sau khi gửi dữ liệu đi sẽ trả về ngay lập tức. Và hệ thống sẽ phải gọi một hàm khác như select() để quan sát tình trạng của việc gửi dữ liệu. Trên môi trường Windows chúng ta cũng có thể sử dụng các hàm non-blocking. Tuy nhiên các nhà thiết kế winsock còn đưa ra các hàm bất đồng bộ.[3]

Các hàm bất đồng bộ được đưa ra dựa trên cơ chế hoạt động message-driven của môi trường Windows. Chúng ta lấy ví dụ là các hàm gửi nhận dữ liệu. Việc gửi dữ liệu không nhất thiết phải diễn ra ngay lập tức, và việc nhận dữ liệu sẽ bắt buộc chương trình phải chờ trừ phi nó nhận được một hằng đặc biệt. Bằng cách tạo socket ở

chế độ non-blocking để dùng các hàm non-blocking và kết hợp với hàm WSAAssyncSelect(), ứng dụng sẽ nhận được các message thông báo sự kiện để báo cho chương trình biết khi nào chương trình có thể gửi dữ liệu đi hoặc đã có dữ liệu truyền đến cần đọc ra từ socket. Trong các khoảng thời gian còn lại, khi không có thông báo các phần khác của hệ thống có thể thực thi được.

Các hàm bất đồng bộ rất phù hợp cho các hoạt động diễn ra trên môi trường Windows 16 bits là môi trường nonpreemptive. Trong môi trường Win32 như Windows NT hay Windows98 là môi trường preemptive các hàm blocking vẫn có thể sử dụng được. Tuy nhiên việc dùng các hàm bất đồng bộ trên môi trường Win32 giúp chương trình đáp ứng tốt hơn cho việc tương tác với người sử dụng. Một hàm blocking sẽ ngăn trở hệ thống đáp ứng kịp thời cho các thao tác của người sử dụng.

Điều này rất quan trọng trên một môi trường giao diện như Windows. Vì vậy các hàm bất đồng bộ vẫn được sử dụng.

Vì môi trường Windows98 có hỗ trợ cơ chế lập trình song song thông qua việc định thời thực thi cho các thread, do đó trong việc thiết kế, chúng ta chọn dùng cơ chế blocking và thực hiện việc lập trình socket bằng các đối tượng do MFC cung cấp là các lớp CAsyncSocket, CSocket, CSocketFile, CArchive. Việc chọn lập trình bằng công cụ này vì có nhữnh đặc điểm sau:

Các lớp đối tượng đều do MFC hỗ trợ, phù hợp với cấu trúc chương trình được xây dựng dựa trên các lớp đối tượng MFC. Ứng dụng được xây dựng trên các lớp đối tượng MFC bằng các công cụ AppWizard, ClassWizard. Việc viết ứng dụng sẽ dễ dàng và đơn giản hơn. Và khi ứng dụng có hỗ trợ socket thông qua các lớp đối tượng socket của MFC ở trên, việc lập trình sẽ trở nên tiên lợi hơn.

Việc lập trình socket trên các lớp đối tượng thường dễ dàng và đơn giản hơn so với việc lập trình bằng các hàm socket nguyên thủy được hỗ trợ bởi Windows SDK.

Chúng ta lấy một ví dụ như sau: tạo một socket và lắng nghe ở một port xác định.[6]

Lập trình bằng công cụ do Windows SDK hỗ trợ:

// Tạo Socket

SOCKET hSocket = socket ( int af = PF_INET, int type = SOCK_STREAM, int protocol = 0);

// Ràng buộc socket vào một port cố định SOCKADDR_IN sin;

u_short alport = IPPORT_RESERVED;

sin.sin_family = AF_INET;

sin.sin_addr.s_addr = 0;

for (;;) {

sin.sin_port = htons(alport);

if (bind(hSocket, (LPSOCKADDR)&sin, sizeof (sin)) == 0){

/* it worked */

}

if ( GetLastError != WSAEADDRINUSE) { /* fail */

}

alport--;

if (alport == IPPORT_RESERVED/2 ) {

/* fail--all unassigned reserved ports are */

/* in use. */

} }

// Lắng nghe lời gọi liên kết

int listen ( hSocket, int backlog = 5 );

Trong khi đó nếu chúng ta lập trình bằng các lớp socket do MFC hỗ trợ thì các công việc phải thực thi như sau:

// Tạo lớp đối tượng

CSocket* m_pSocket = new CSocket;

// Tạo socket và ràng buộc vào một port xác định

m_pSocket->Create(nPort);

// Lắng nghe lời gọi liên kết m_pSocket->Listen();

Khi lập trình chúng ta chọn các hàm blocking vì chúng được hỗ trợ bởi công cụ lập trình serialize. Cơ chế serialize cho phép hệ thống đảm bảo việc truyền nhận dữ liệu trên socket. Việc lập trình socket thông qua cơ chế serialize cũng đơn giản và dễ dàng hơn. Vì chương trình được hiện thực trên môi trường Windows98 cho nên chúng ta sẽ thực thi vào các hàm truyền nhận của socket. Vì vậy các hàm blocking cũng không ảnh hưởng nhiều đến việc thực thi của chương trình cũng như trong toàn hệ thống.

Ngoài ra việc dùng cơ chế Serialize (Serialization là một quá trình đọc một đối tượng dữ liệu từ đĩa hay ngược lại, ghi chúng lên dĩa. MFC hỗ trợ cơ chế serialization trong class object vì vậy bất cứ đối tượng nào dẫn xuất từ object đều thừa hưởng cơ chế serialization) cũng đồng nghĩa với việc chúng ta dùng giao thức TCP trong việc truyền nhận dữ liệu. Việc dùng giao thức này giúp quá trình trao đổi dữ liệu được diễn ra tin cậy hơn. Dĩ nhiên phí tổn hệ thống phải bỏ ra cũng cao hơn.

CHƯƠNG V

THIẾT KẾ CHƯƠNG TRÌNH

TRUYỀN ÂM THANH TRÊN MẠNG LAN

V.1 MÔI TRƯỜNG VÀ CÔNG CỤ LẬP TRÌNH

Một phần của tài liệu Thiết kế chương trình truyền tiếng nói qua mạng LAN thông qua sự trợgiúp của công cụ SDK (Trang 45 - 50)

Tải bản đầy đủ (DOC)

(82 trang)
w