1. Trang chủ
  2. » Công Nghệ Thông Tin

Tài liệu Lập trình Mạng Microsoft .NET Framework phần cuối doc

9 410 2
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Sử dụng TCP một cách bất đồng bộ
Trường học University of Information Technology
Chuyên ngành Network Programming
Thể loại Tài liệu
Thành phố Ho Chi Minh City
Định dạng
Số trang 9
Dung lượng 179,92 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

1.1 Sử dụng TCP một cách bất đồng bộ V Bạn cần ghi dữ liệu ra network-stream từng khối một, mà không phải block phần mã lệnh còn lại.. Sử dụng các phương thức này, bạn có thể gửi hay n

Trang 1

1.1 Sử dụng TCP một cách bất đồng bộ

V Bạn cần ghi dữ liệu ra network-stream từng khối một, mà không phải block phần mã lệnh còn lại Kỹ thuật này có thể được sử dụng nếu bạn muốn

“stream” một file lớn trên mạng

# Tạo một lớp riêng để xử lý kỹ thuật streaming bất đồng bộ Bạn có thể bắt đầu

“stream” một khối dữ liệu bằng phương thức NetworkStream.BeginWrite và cung cấp một phương thức callback Khi callback được kích hoạt thì gửi khối

kế tiếp

Lớp NetworkStream hỗ trợ việc sử dụng bất đồng bộ thông qua phương thức BeginRead

và BeginWrite Sử dụng các phương thức này, bạn có thể gửi hay nhận một khối dữ liệu

trên một trong các tiểu trình do thread-pool của bộ thực thi NET cung cấp, mà không

block mã lệnh của bạn Mục này trình bày kỹ thuật ghi bất đồng bộ

Khi gửi dữ liệu một cách bất đồng bộ, bạn phải gửi dữ liệu nhị phân thô (một mảng byte)

Và bạn cần chọn kích thước mỗi lần gửi hay nhận Ví dụ dưới đây viết lại server từ mục

11.11 sao cho mỗi lớp ClientHandler gửi một lượng lớn dữ liệu được đọc từ một file Dữ liệu này được gửi một cách bất đồng bộ, nghĩa là ClientHandler có thể tiếp tục thực hiện các tác vụ khác (trong ví dụ này, nó chỉ việc lấy các thông điệp được gửi từ client)

Một thuận lợi của cách tiếp cận này là toàn bộ nội dung của file chẳng bao giờ nằm trong

bộ nhớ một lượt Thay vào đó, nó được thu lấy ngay trước khi một khối mới được gửi Một thuận lợi khác nữa là server có thể hủy bỏ thao tác vào bất cứ lúc nào Ví dụ, nếu client chỉ đọc đến khối dữ liệu thứ ba thì ngắt kết nối, server sẽ thiết lập một biến thành viên luận lý có tên là fileStop để báo cho callback không gửi dữ liệu nữa

Dưới đây là lớp ClientHandler đã được sửa đổi (lớp TcpServerTest không cần thay đổi gì):

using System;

using System.Net;

using System.Net.Sockets;

using System.IO;

using SharedComponent;

public class ClientHandler {

private TcpClient client;

private string ID;

// Kích thước một khối dữ liệu (2 KB)

Trang 2

private int bufferSize = 2048;

// Bộ đệm dùng để chứa dữ liệu

private byte[] buffer;

// Dùng để đọc dữ liệu từ một file

private FileStream fileStream;

// Dùng để giao tiếp với client

private NetworkStream networkStream;

// Dấu hiệu ngừng gửi dữ liệu

private bool fileStop = false;

public ClientHandler(TcpClient client, string ID) {

this.buffer = new byte[bufferSize];

this.client = client;

this.ID = ID;

}

public void Start() {

// Thu lấy network stream

networkStream = client.GetStream();

// Tạo các đối tượng dùng để gửi và nhận text

BinaryWriter w = new BinaryWriter(networkStream); BinaryReader r = new BinaryReader(networkStream);

if (r.ReadString() == ClientMessages.RequestConnect) {

w.Write(ServerMessages.AcknowledgeOK);

Console.WriteLine(ID + ": Connection completed.");

string message = "";

while (message != ClientMessages.Disconnect) { message = r.ReadString();

if (message == ClientMessages.RequestData) {

Trang 3

// Tên file có thể do client cung cấp, nhưng

// trong ví dụ này, file thử nghiệm là mã cứng

fileStream =

new FileStream("test.bin", FileMode.Open);

// Gửi kích thước file

w.Write(fileStream.Length.ToString());

// Khởi chạy thao tác bất đồng bộ

StreamData(null);

}

}

fileStop = true;

Console.WriteLine(ID + ": Disconnect request received."); } else {

Console.WriteLine(ID + ": Could not complete connection."); }

// Đóng kết nối

client.Close();

Console.WriteLine(ID + ": Client connection closed.");

Console.ReadLine();

}

private void StreamData(IAsyncResult asyncResult) {

// Hủy bỏ nếu client ngừng kết nối

if (fileStop == true) {

fileStop = false;

return;

}

if (asyncResult != null) {

// Một khối đã được ghi một cách bất đồng bộ

networkStream.EndWrite(asyncResult);

}

// Lấy khối kế tiếp từ file

int bytesRead = fileStream.Read(buffer, 0, buffer.Length);

Trang 4

// Nếu không đọc được byte nào, stream đã đến cuối file

if (bytesRead > 0) {

Console.WriteLine("Streaming new block.");

// Ghi khối kế tiếp ra network stream

networkStream.BeginWrite(buffer, 0, buffer.Length,

new AsyncCallback(StreamData), null);

} else {

// Kết thúc thao tác

Console.WriteLine("File streaming complete.");

fileStream.Close();

}

}

}

Bạn có thể sử dụng một mẫu tương tự để đọc dữ liệu một cách bất đồng bộ phía client

V Bạn cần gửi dữ liệu giữa hai máy tính trên một network bằng User Datagram

Protocol (UDP) stream

# Sử dụng lớp System.Net.Sockets.UdpClient, và sử dụng hai tiểu trình: một để

gửi dữ liệu và một để nhận dữ liệu

UDP là một giao thức phi kết nối, không có bất kỳ điều khiển dòng chảy hay kiểm tra lỗi

nào Khác với TCP, UDP sẽ không được sử dụng ở những nơi cần đến giao tiếp đáng tin

cậy Tuy nhiên, vì chi phí thấp hơn, UDP thường được sử dụng cho các ứng dụng

"chatty", tại đó chấp nhận mất một vài thông điệp Ví dụ, giả sử bạn muốn tạo một

network mà trong đó, các client gửi thông tin về nhiệt độ hiện thời tại vị trí của chúng

đến một server mỗi vài phút Bạn có thể sử dụng UDP trong trường hợp này vì tần số

giao tiếp cao và thiệt hại do mất packet là không đáng kể (vì server có thể tiếp tục sử

dụng nhiệt độ nhận được cuối cùng)

Ứng dụng dưới đây sử dụng hai tiểu trình: một để nhận thông điệp và một để gửi thông

điệp Để thử nghiệm ứng dụng này, hãy nạp hai thể hiện cùng một lúc Trên máy tính A,

cho biết địa chỉ IP của máy tính B Trên máy tính B, cho biết địa chỉ IP của máy tính A

Theo đó, bạn có thể gửi qua lại thông điệp dạng text (bạn có thể mô phỏng thử nghiệm

này trên một máy đơn bằng cách sử dụng hai port khác nhau và địa chỉ loopback)

using System;

Trang 5

using System.Text;

using System.Net;

using System.Net.Sockets;

using System.Threading;

public class UdpTest {

private static int localPort;

private static void Main() {

// Định nghĩa endpoint (thông điệp được gửi tại đây)

Console.Write("Connect to IP: ");

string IP = Console.ReadLine();

Console.Write("Connect to port: ");

int port = Int32.Parse(Console.ReadLine());

IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Parse(IP), port);

// Định nghĩa endpoint cục bộ (thông điệp được nhận tại đây)

Console.Write("Local port for listening: ");

localPort = Int32.Parse(Console.ReadLine());

Console.WriteLine();

// Tạo một tiểu trình mới để nhận thông điệp đến

Thread receiveThread = new Thread(

new ThreadStart(ReceiveData));

receiveThread.IsBackground = true;

receiveThread.Start();

UdpClient client = new UdpClient();

try {

string text;

do {

text = Console.ReadLine();

Trang 6

if (text != "") {

// Mã hóa dữ liệu thành dạng nhị phân

// bằng phép mã hóa UTF8

byte[] data = Encoding.UTF8.GetBytes(text);

// Gửi text đến client ở xa

client.Send(data, data.Length, remoteEndPoint);

}

} while (text != "");

} catch (Exception err) {

Console.WriteLine(err.ToString());

}

Console.ReadLine();

}

private static void ReceiveData() {

UdpClient client = new UdpClient(localPort);

while (true) {

try {

// Nhận dữ liệu (byte)

IPEndPoint anyIP = new IPEndPoint(IPAddress.Any, 0); byte[] data = client.Receive(ref anyIP);

// Chuyển byte thành text bằng phép mã hóa UTF8 string text = Encoding.UTF8.GetString(data);

// Hiển thị text thu được

Console.WriteLine(">> " + text);

} catch (Exception err) {

Console.WriteLine(err.ToString());

}

}

}

}

Trang 7

Chú ý rằng, các ứng dụng UDP không thể sử dụng NetworkStream như các ứng dụng

TCP Thay vào đó, chúng phải chuyển tất cả dữ liệu thành một stream bằng một lớp mã

hóa, như đã được mô tả trong mục 2.2

Bạn có thể thử nghiệm ứng dụng này với các client trên máy cục bộ bằng cách sử dụng

hai port khác nhau và địa chỉ loopback Ví dụ, giả sử có hai UDP-client: client A và client

B Dưới đây là transcript đối với client A:

Connect to IP: 127.0.0.1

Connect to port: 8001

Local port for listening: 8080

Hi there!

Và đây là transcript tương ứng đối với client B (cùng với thông điệp nhận được):

Connect to IP: 127.0.0.1

Connect to port: 8080

Local port for listening: 8001

>> Hi there!

V Bạn cần gửi e-mail đến một địa chỉ e-mail bằng một SMTP-server (Simple Mail

Transfer Protocol server)

# Sử dụng lớp SmtpMail và MailMessage thuộc không gian tên System.Web.Mail

Các lớp trong không gian tên System.Web.Mail cung cấp một vỏ bọc cho thành phần

Collaboration Data Objects for Windows 2000 (CDOSYS) Chúng cho phép bạn soạn và

gửi thông điệp e-mail bằng SMTP

Dễ dàng sử dụng các kiểu này Bạn chỉ cần tạo một đối tượng MailMessage, cho biết địa chỉ e-mail của người gửi và người nhận, và đặt nội dung của thông điệp trong thuộc tính Body

MailMessage myMessage = new MailMessage();

myMessage.To = "someone@somewhere.com";

myMessage.From = "me@somewhere.com";

myMessage.Subject = "Hello";

myMessage.Priority = MailPriority.High;

myMessage.Body = "This is the message!";

Nếu muốn, bạn có thể gửi một thông điệp HTML bằng cách thay đổi định dạng của thông điệp và sử dụng các thẻ HTML

Trang 8

myMessage.BodyFormat = MailFormat.Html;

myMessage.Body = @"<HTML><HEAD></HEAD>" +

@"<BODY>This is the message!</BODY></HTML>";

Bạn có thể thêm file đính kèm bằng tập hợp MailMessage.Attachments và lớp MailAttachment

MailAttachment myAttachment = new MailAttachment("c:\\mypic.gif");

myMessage.Attachments.Add(myAttachment);

Để gửi thông điệp, bạn chỉ cần cho biết tên của SMTP-server và gọi phương thức

SmptMail.Send

SmtpMail.SmtpServer = "test.mailserver.com";

SmtpMail.Send(myMessage);

Tuy nhiên, có một vài vấn đề khi sử dụng lớp SmtpMail để gửi một thông điệp e-mail

Lớp này cần một SMTP-server cục bộ hay một relay-server trên mạng Ngoài ra, lớp SmtpMail không hỗ trợ việc xác thực, do đó, nếu SMTP-server yêu cầu username và

password, bạn sẽ không thể gửi bất kỳ mail nào Để khắc phục vấn đề này, bạn có thể

trực tiếp sử dụng thành phần CDOSYS thông qua COM Interop (giả sử bạn có phiên bản server của Windows hay Microsoft Exchange)

# Nhớ rằng, giao thức SMTP không được sử dụng để lấy e-mail Đối với công việc này, bạn cần giao thức POP3 hay IMAP, cả hai giao thức này đều không có trong NET Framework

Để có thêm thông tin về cách sử dụng và cấu hình SMTP-server, bạn hãy tham khảo các quyển sách chuyên về IIS

V Bạn muốn gửi một thông điệp e-mail, nhưng SMTP-server (Simple Mail

Transfer Protocol server) chưa được cấu hình trên máy tính

# Sử dụng Simple MAPI (Messaging Application Programming Interface) bằng cách nhập hàm cần thiết từ thư viện hệ thống không-được-quản-lý Mapi32.dll

MAPI là giao diện cho phép bạn tương tác với các tính năng mailing được tích hợp trong

hệ điều hành Windows Bạn có thể sử dụng MAPI (thông qua các hàm API không-được-quản-lý, hoặc thông qua thành phần MAPI đi cùng với Visual Studio 6) để tương tác với mail-client mặc định (thường là Microsoft Outlook hay Outlook Express) Các tác vụ bao gồm: lấy thông tin contact từ sổ địa chỉ, lấy thông điệp trong Inbox, soạn và gửi thông điệp Đáng tiếc, không có lớp nào sử dụng MAPI trong NET Framework Tuy nhiên, bạn

có thể sử dụng thư viện không-được-quản-lý Mapi32.dll

Thách thức chính khi sử dụng Simple MAPI trong NET là marshal các cấu trúc được sử dụng trong NET thành các cấu trúc mà Simple MAPI cần, sau đó marshal các cấu trúc do

Trang 9

Simple MAPI trả về cho ứng dụng NET Đây không phải là một công việc đơn giản Tuy

nhiên, Microsoft cung cấp một giải pháp toàn vẹn trong một thành phần C# tổng quát (có

thể tải miễn phí) Bạn có thể sử dụng hai dự án dưới đây:

• Một thành phần thư viện lớp (Class Library Component) bọc lấy các hàm Simple

MAPI và làm cho chúng có hiệu lực thông qua các phương thức của lớp

• Một chương trình (thử nghiệm) sử dụng thành phần này để đăng nhập, đăng xuất, đọc mail, gửi mail

Mã lệnh của cả hai dự án này không mấy phức tạp, nhưng rất dài nên không trình bày ở đây (bạn hãy xem trong đĩa CD đính kèm)

# Đối với một ví dụ phức tạp hơn (xây dựng trên thư viện Simple MAPI của

Microsoft để tạo một ứng dụng Windows Form), một dự án C# mẫu (có thể tải

miễn phí) được Thomas Scheidegger cung cấp tại [http://www.codeproject.com/

csharp/simplemapidotnet.asp]

Ngày đăng: 26/01/2014, 04:20

TỪ KHÓA LIÊN QUAN

w