Tải bản đầy đủ (.doc) (54 trang)

VIẾT CHƯƠNG TRÌNH TRÒ CHUYỆN ĐƠN GIẢN BẰNG NGÔN NGỮ LẬP TRÌNH C.

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (997.93 KB, 54 trang )

Muc Lục
Muc Lục.............................................................................................................................................1
LỜI MỞ ĐẦU......................................................................................................................................1
LỜI CẢM ƠN......................................................................................................................................3
NHẬN XÉT CỦA GIÁO VIÊN HƯỚNG DẪN...........................................................................................4
Chương 1: CƠ SỞ LÝ THUYẾT VÀ ỨNG DỤNG....................................................................................5
1.1.Sơ lược về lập trình Socket......................................................................................................5
1.1.1.Khái niệm IPAddress và Port.............................................................................................5
1.1.2.Lớp IPAddress...................................................................................................................5
1.1.3.Lớp IPEndPoint.................................................................................................................6
1.1.4.Lập trình Socket hướng kết nối(TCP).................................................................................6
1.1.5.Lập trình Socket phi kết nối(UDP).....................................................................................7
1.1.6.Lớp Helper của C# Socker.................................................................................................8
1.2.Xử lý tiến trình trong lập trình đa luồng................................................................................12
1.2.1.Khái niệm luồng..............................................................................................................12
1.2.2.Khảo sát namespace System.Threading..........................................................................13
1.3.Đồng bộ và bất đồng bộ trong lập trình đa luồng..................................................................16
1.4.Hệ mã hóa công khai RSA......................................................................................................19
1.4.1.Khái niệm mã hóa...........................................................................................................19
1.4.2.Hệ mã khóa.....................................................................................................................21
1.4.3.Thuật toán mã hóa RSA...................................................................................................22
Chương 2: PHÂN TÍCH VÀ THIẾT KẾ CHƯƠNG TRÌNH......................................................................27
2.1.Phân tích................................................................................................................................27
2.1.1.Phân tích nhu cầu thực tiễn............................................................................................27
2.1.2.Yêu cầu đề ra...................................................................................................................27
2.1.3.Phân tích các thành phần xử lý.......................................................................................27
2.1.4.Quá trình xử lý của chương trình....................................................................................35
2.2.Thiết kế..................................................................................................................................41


2.2.1.Thiết kế Server................................................................................................................41


2.2.2.Thiết kế Client.................................................................................................................44
2.3.Cài đặt và sử dụng chương trình............................................................................................48
KẾT LUẬN.........................................................................................................................................50
DANH MỤC TÀI LIỆU THAM KHẢO...................................................................................................51


DANH SÁCH HÌNH VẼ SƠ ĐỒ
Hình 1.1 Lập trình socket hướng kết nối (TCP).........................................................6
Hình 1.2 Lập trình socket phi kết nối (UDP) ..............................................................8
Hình 1.3 Kết quả chương trình đồng bộ hóa .............................................................18
Hình 1.4 Kết quả chương trình bất đồng bộ..............................................................18
Hình 1.5 Mã hóa ................................................................................................ .........20
Hình
1.6

hóa

giải

thông
tin
được
truyền
đi................................ ...............20
Hình 1.7 Mã hóa bí mật............................................................... ...............................21
Hình
1.8

hóa
công

khai
............................................................... .........................21
Hình
2.1

đồ
xử

đăng
nhập................................................................ .................28
Hình
2.2

đồ
xử

đăng
xuất................................................................. .................29
Hình 2.3 Sơ đồ xử lý gởi tin nhắn................................................................ ..............30
Hình
2.4
Giao
diện
Server
thu
gọn................................................................ .............42
Hình
2.5.a
Giao
diện

Server
mở
rộng
chưa
kết
nối............................................. ...........43
Hình 2.5.b Giao diện Server mở rộng đã có kết nối..................................................43
Hình
2.6
Giao
diện
Client
đăng
nhập ................................................................ .........44
Hình
2.7
Giao
diện
Client
chính
thu
gọn
.................................................................. .45
Hình
2.8
Giao
diện
Client
Chat
room

................................................................ ........46
Hình
2.9
Giao
din
Client
tin
nhắn
riêng
tư.................................................................47
Hình
2.10
Giao
diện
Client
Chat
riêng

..................................................................48


Khóa luận tốt nghiệp

GVHD: Th.S Ngô Đình Thưởng
LỜI MỞ ĐẦU

Với sự phát triển của Internet hiện nay, việc viết các phần mềm ứng dụng
mạng đã trở nên cần thiết và phổ biến với những nhà phát triển phần mềm. Với
nhu cầu trao đổi thông tin, liên lạc và trò chuyện trên mạng ngày càng tăng hiện
nay, việc nghiên cứu và xây dựng thành công một chương trình Chat sẽ đáp ứng

được những nhu cầu cần thiết đó và làm phong phú thêm các phương thức trao
đổi và trò chuyện của các chương trình Chat hiện nay.
Với những lý do đặt ra như thế, việc nghiên cứu và xây dựng nên một
chương trình Chat phải đảm bảo các tính năng cần thiết và cơ bản nhất như: có
thể gởi tin nhắn riêng tư hoặc trong một nhóm giữa các user, tạo ra danh sách
bạn bè... Việc nghiên cứu và xây dựng một chương trình Chat cần thực hiện một
cách kĩ lưỡng và khoa học nhất để có thể tạo ra một ứng dụng có với những tính
năng cần thiết, dể dàng sử dụng, tao tác linh hoạt.
Để xây dựng thành công một chương trình Chat, em đã tập trung vào những
đối tượng và phạm vi nghiên cứu sau:
 Đối tượng nghiên cứu: tìm hiểu cơ chế hoạt động của Socket, các nguyên lý
về lập trình đa luồng, đồng bộ và bất đồng bộ trong lập trình đa luồng, cuối
cùng là ứng dụng hệ mã hóa công khai RSA để mã hóa thông tin truyền đi
trên mạng.
 Phạm vi nghiên cứu: tạo ra một chương trình Chat với tính năng như gởi và
nhận tin nhắn dạng text giữa các users với dạng riêng tư hoặc trong một
nhóm, mã hóa và giải mã thông tin trước khi truyền đi và sau khi nhận được
nhằm đảm bảo tính riêng tư và bảo mật khi truyền dữ liệu. Tất cả các quá
trình đó được giám sát và điều khiển bởi một Server.
Trong báo cáo này em xin trình bày theo kết cấu:
Chương I: CƠ SỞ LÝ THUYẾT VÀ ỨNG DỤNG
Tìm hiểu về lập lập trình Socket bằng ngôn ngữ C#, đưa ra cái nhìn tổng quan
cơ sở lý thuyết chủ đạo trong quá trình xây dựng chương trình. Tìm hiểu và ứng
dụng hệ mã hóa công khai RSA trong quá trình mã hóa thông tin trước khi truyền
đi.
Chương II: PHÂN TÍCH VÀ THIẾT KẾ CHƯƠNG TRÌNH
SVTH: Nguyễn Văn Xuân

Trang 1



Khóa luận tốt nghiệp

GVHD: Th.S Ngô Đình Thưởng

Đưa ra các bước phân tích từ nghiên cứu thực tế của người sử dụng và vận
dụng cơ sở lý thuyết trong việc quá trình xây dựng chương trình. Đề ra các giải
pháp trong từng bước phân tích nhằm xây dựng chương trình một cách khoa học
nhất.
Chương III: CÀI ĐẶT VÀ SỬ DỤNG CHƯƠNG TRÌNH
Là cách hướng dẫn người sử dụng phương pháp cài đặt chương trình, yêu
cầu hệ thống và các phương pháp sử dụng chương trình.

SVTH: Nguyễn Văn Xuân

Trang 2


Khóa luận tốt nghiệp

GVHD: Th.S Ngô Đình Thưởng
LỜI CẢM ƠN

Bằng sự nổ lực và kiên trì học hỏi trong quá trình thự c h iệ n kh óa luậ n ,
em đã hoàn thành đề tài “Viết chương trình trò chuyện đơn giản bằng
ngôn ngữ lập trình C#” với sự hướng dẫn của Thầy Ngô Đình Thưởng.
Em xin chân thành cảm ơn Thầy Ngô Đình Thưởng đã hướng dẫn em thực
hiện khóa luận tốt nghiệp. Thầy đã nhiệt tình hướng dẫn và giải đáp mọi thắc mắc
trong quá trình thực hiện khóa luận.
Em cũng xin chân thành gởi lời cảm ơn đến Thầy Cô trong khoa Tin học, các

Anh chị và các bạn đã giúp đỡ trong suốt quá trình thực hiện khóa luận tốt nghiệp.
Cuối cùng xin chúc quý Thầy cô, các Anh chị cùng các bạn sức khỏe và công tác
tốt!
Đà Nẵng, ngày 15 tháng 05 năm 2013
Sinh viên thực hiện
Nguyễn Văn Xuân

SVTH: Nguyễn Văn Xuân

Trang 3


Khóa luận tốt nghiệp

GVHD: Th.S Ngô Đình Thưởng

NHẬN XÉT CỦA GIÁO VIÊN HƯỚNG DẪN
………………………………………………………………………………………
………………………………………………………………………………………
………………………………………………………………………………………
………………………………………………………………………………………
………………………………………………………………………………………
………………………………………………………………………………………
………………………………………………………………………………………
………………………………………………………………………………………
………………………………………………………………………………………
………………………………………………………………………………………
………………………………………………………………………………………
………………………………………………………………………………………
………………………………………………………………………………………

………………………………………………………………………………………
Đà Nẵng, ngày ... tháng ... năm 2013
Giáo viên hướng dẫn

Ngô Đình Thưởng

SVTH: Nguyễn Văn Xuân

Trang 4


Khóa luận tốt nghiệp

GVHD: Th.S Ngô Đình Thưởng

Chương 1: CƠ SỞ LÝ THUYẾT VÀ ỨNG DỤNG
1.1. Sơ lược về lập trình Socket
1.1.1. Khái niệm IPAddress và Port
Nguyên lý: Trong một máy có rất nhiều ứng dụng muốn trao đổi với các
ứng dụng khác thông qua mạng (VD: Có 2 ứng dụng trên máy A muốn trao đổi
với 2 ứng dụng trên máy B). Mỗi máy tính chỉ có duy nhất một đường truyền dữ
liệu (để gửi và nhận dữ liệu cho nhau).
Vấn đề: Rất có thể xảy ra "nhầm lẫn" khi dữ liệu từ máy A gửi đến máy B
thì không biết là dữ liệu đó gửi cho ứng dụng nào trên máy B? Trong quá trình
truyền và nhận dữ liệu có thể xảy ra lỗi làm mất mát hoặc sai lệch dữ liệu.
Giải quyết: Mỗi ứng dụng trên máy B sẽ được gán một số hiệu (gọi là cổng
Port), số hiệu cổng này từ 1..65535. Khi ứng dụng trên máy A muốn gửi cho ứng
dụng nào trên máy B thì chỉ việc điền thêm số hiệu cổng (vào trường
RemotePort) vào gói tin cần gửi. Trên máy B, các ứng dụng sẽ việc kiểm tra giá trị
cổng trên mỗi gói tin xem có trùng với số hiệu cổng của mình (đã được gán – chính

là giá trị Localport) hay không? Nếu bằng thì xử lý, còn trái lại thì không làm gì.
Như vậy khi cần trao đổi dữ liệu cho nhau thì hai ứng dụng cần phải biết
thông tin tối thiểu là địa chỉ IP (IP Address) và số hiệu cổng (Port) của ứng dụng
kia.
1.1.2. Lớp IPAddress
IPAddress : là một lớp dùng để mô tả một địa chỉ IP, lớp này có thể sử
dụng trong nhiều phương thức của Socket. Một số phương thức của lớp IPAddress.
Phương thức:
• Equals: So sánh 2 địa chỉ IP.
• GetHashCode: Lấy giá trị hash cho một đối tượng IPAddress.
• GetType: Trả về kiểu của một thể hiện địa chỉ IP.
• HostToNetworkOrder: Chuyển một địa chỉ IP từ host byte order thành
network dy order IsLoopBack. Cho biết địa chỉ IP có phải là địa chỉ LoopBack
hay không.

SVTH: Nguyễn Văn Xuân

Trang 5


Khóa luận tốt nghiệp

GVHD: Th.S Ngô Đình Thưởng

1.1.3. Lớp IPEndPoint
IPEndPoint là một một lớp các đối tượng mô tả sự kết hợp của một địa chỉ IP
và Port. Đối tượng trong lớp IPEndPoint được dùng để gắn kết các Socket với các
địa chỉ cục bộ hoặc các địa chỉ từ xa.
Hai thuộc tính của IPEndPoint có thể được dùng để lấy được vùng các port trên
hệ thống là MinPort và MaxPort.

1.1.4. Lập trình Socket hướng kết nối(TCP)
Trong lập trình Socket hướng kết nối, giao thức TCP được dùng để thành lập
phiên làm việc giữa hai EndPoint. Khi sử dụng giao thức TCP để thành lập kết nối
ta phải đàm phán kết nối trước nhưng khi kết nối đã được thành lập dữ liệu có thể
truyền đi giữa các thiết bị một cách tin tưởng.
Để lập trình Socket hướng kết nối ta phải thực hiện một loạt các thao tác giữa
Client và Server như trong mô hình bên dưới.

Hình 1.1 Lập trình socket hướng kết nối (TCP)
Sử dụng C# Stream với TCP:
Điều khiển thông điệp dùng giao thức TCP thường gây ra khó khăn cho các lập
trình viên nên .NET Framework cung cấp một số lớp để giảm gánh nặng lập trình.

SVTH: Nguyễn Văn Xuân

Trang 6


Khóa luận tốt nghiệp

GVHD: Th.S Ngô Đình Thưởng

Một trong những lớp đó là NetworkStream, và 2 lớp dùng để gởi và nhận Text
sử dụng giao thức TCP là StreamWriter và StreamReader.
Lớp NetworkStream nằm trong namespace System.Net.Sockets, lớp này có
nhiều phương thức tạo lập để tạo một thể hiện của lớp NetworkStream nhưng
phương thức tạo lập sau hay được dùng nhất:
Socket

server


=

new

Socket(AddressFamily.InterNetwork,

SocketType.Stream, ProtocolType.TCP);
NetworkStream ns = new NetworkStream(server);

Namespace System.IO chứa 2 lớp StreamReader và StreamWriter điều khiển
việc đọc và ghi các thông điệp text từ mạng. Cả 2 lớp đều có thể được triển khai với
một đối tượng NetworkStream để xác định các hệ thống đánh dấu cho các thông
điệp TCP.
Lớp StreamReader có nhiều phương thức tạo lập, trong đó phương thức tạo
lập đơn giản nhất của lớp StreamReader là :
public StreamReader(Stream stream);

Biến stream có thể được tham chiếu đến bất kì kiểu đối tượng Stream nào kể cả
đối tượng NetworkStream. Có nhiều phương thức và thuộc tính có thể được
dùng với đối tượng StreamReader sau khi nó được tạo ra.
Tương tự đối tượng StreamReader, đối tượng StreamWriter có thể được tạo
ra từ một đối tượng NetworkStream:
public StreamWriter(Stream stream);

StreamWriter cũng có nhiều phương thức và thuộc tính kết hợp với nó, một
số phương thức và thuộc tính của lớp StreamReader cũng có trong đối tượng
của StreamWrite.
1.1.5. Lập trình Socket phi kết nối(UDP)
Các Socket phi kết nối cho phép gởi các thông điệp mà không cần phải thiết lập

kết nối trước. Một phương thức đọc toàn bộ thông điệp được gởi bởi một
phương thức gởi, điều này làm tránh được các rắc rối, phức tạp với biên dữ liệu.
Thật không may mắn là giao thức phi kết nối UDP không đảm bảo dữ liệu được
truyền tới đích. Nhiều yếu tố như mạng bận, mạng bị ngắt kết nối giữa chừng có
thể ngăn cản các gói tin được truyền tới đích.
Nếu một thiết bị chờ dữ liệu từ một thiết bị ở xa, nó phải được gán một địa chỉ
SVTH: Nguyễn Văn Xuân

Trang 7


Khóa luận tốt nghiệp

GVHD: Th.S Ngô Đình Thưởng

và port cục bộ, dùng hàm Bin() để gán. Một khi đã thực hiện xong, thiết bị có thể
dùng Socket để gởi dữ liệu ra ngoài hay nhận dữ liệu từ Socket.
Bởi vì thiết bị Client không tạo ra kết nối đến một địa chỉ Server cụ thể do đó
phương thức Connect() không cần dùng trong chương trình UDP Client. Mô hình
bên dưới mô tả các bước lập trình Socket phi kết nối.

Hình 1.2 Lập trình socket phi kết nối (UDP)
1.1.6.

Lớp Helper của C# Socker

1.1.6.1. Lớp TCPClient:
Lớp TCPClient nằm trong namespace System.Net.Sockets được thiết kế để
hổ trợ cho việc viết ứng dụng của TCP Client được dể dàng. Lớp TcpClient
cho phép tạo ra một đối tượng Tcp Client, sử dụng một trong ba phương thức tạo

lập như sau:
• TcpClient(): Là phương thức tạo lập đầu tiên, đối tượng được tạo ra
bởi phương thức tạo lập này sẽ gắn kết với một địa chỉ cục bộ và một
Port TCP ngẫu nhiên. Sau khi đối tượng TcpClient được tạo ra, nó phải
được kết nối đến thiết bị ở xa thông qua phương thức Connect như ví dụ
dưới đây:
TcpClient newcon = new TcpClient();
Newcon.Connect(“192.168.1.1”,2011);

SVTH: Nguyễn Văn Xuân

Trang 8


Khóa luận tốt nghiệp


GVHD: Th.S Ngô Đình Thưởng

TcpClient(IPEndPoint localEP): Phương thức tạo lập này cho phép

chúng ta chỉ ra địa chỉ IP cục bộ cùng với port được dùng. Đây là phương
thức tạo lập thường được sử dụng khi thiết bị có nhiều hơn một card
mạng và chúng ta muốn dữ liệu được gởi trên card mạng nào. Phương thức
Connect() cũng được dùng để kết nối với thiết bị ở xa:
IPEndPoint iep = new
IPEndPoint(IPAddress,Parse(“192.168.1.1”)2011,);
TcpClient newcon = new TcpClient(iep);
Newcon.Connect(“192.168.1.2”,2011);


• TcpClient(String host, int port): Phương thức tạo lập thứ ba này thường
được sử dụng nhất, nó cho phép chỉ ra thiết bị nhận trong phương thức tạo
lập và không cần phải dùng phương thức Connect(). Địa chỉ của thiết bị ở
xa có thể là một chuỗi hostname hoặc một địa chỉ IP. Phương thức tạo lập
của TcpClient sẽ tự động phân giải hostname thành địa chỉ IP:
TcpClient newcon = new

TcpClient(“”,2011);

• Mỗi khi đối tượng TcpClient được tạo ra, nhiều thuộc tính và phương
thức có thể được dùng để xử lý việc truyền dữ liệu qua lại giữa các thiết bị.
Mỗi khi đối tượng TcpClient được tạo ra, nhiều thuộc tính và phương thức
có thể được dùng để xử lý việc truyền dữ liệu qua lại giữa các thiết bị.
Phương thức:
• Close(): Đóng kết nối TCP.
• Connect(): Thành lập kết nối TCP Client với các thiết bị ở xa.
• Equals(): So sánh hai đối tượng TcpClient.
• GetHashCode(): Lấy mã hash code.
• GetStream(): Lấy đối tượng Stream nó có thể dùng để gởi và nhận dữ
liệu.
• GetType(): Lấy kiểu của thể hiện hiện tạo.
• ToString() Chuyển thể hiện hiện tại sang kiểu chuỗi.
Mỗi khi kết nối được thành lập, phương thức GetStream() gán một đối
tượng NetworkStream để gởi và nhận vào phương thức Read() và Write(). Lớp
TcpClient còn có nhiều thuộc tính được mô tả như sau.
SVTH: Nguyễn Văn Xuân

Trang 9



Khóa luận tốt nghiệp

GVHD: Th.S Ngô Đình Thưởng

Thuộc tính:
• LingerState: Lấy hoặc thiết lập thời gian kết nối TCP vẫn còn sau khi
gọi phương thức Close().
• NoDelay: Lấy hoặc thiết lập thời gian trễ được dùng để gởi hoặc nhận ở
bộ đệm TCP.
• ReceiveBufferSize: Lấy hoặc thiết lập kích thước bộ đệm TCP nhận.
• ReceiveTimeout: Lấy hoặc thiết lập thời gian timeout của Socket.
• SendBufferSize: Lấy hoặc thiết lập kích thước bộ đệm TCP gởi.
• SendTimeout: Lấy hoặc thiết lập giá trị timeout của Socket.
1.1.6.2. Lớp TCPListener:
Cũng giống như lớp TcpClient, lớp TcpListener cũng cho phép chúng ta
tạo ra các chương trình TCP Server một cách đơn giản. Lớp TcpListener có
ba phương thức tạo lập.
• TcpListener(int port): gắn một đối tượng TcpListener vào một port được
chỉ ra trên máy cục bộ.
• TcpListener(IPEndPoint ie): gắn một đối tượng TcpListener vào một
đối tượng IPEndPoint cục bộ.
• TcpListener(IPAddress add, int port): Gắn một đối tượng TcpListener
vào một đối tượng IPAddress và một port.
Không giống như lớp TcpClient, các phương thức tạo lập của lớp
TcpListener yêu cầu ít nhất một tham số: số port mà Server lắng nghe kết
nối. Nếu Server có nhiều card mạng và ta muốn lắng nghe trên một card mạng
nào đó thì ta dùng một đối tượng IPEndPoint để chỉ ra địa chỉ IP của card
mạng cùng với số port dùng để lắng nghe.
Phương thức:
• AcceptSocket(): Chấp nhận kết nối trên port và gán kết nối cho một

đối tượng Socket.
• AcceptTcpClient(): Chấp nhận kết nối trên port và gán kết nối cho một
đối tượng TcpClient.
• Equals(): So sánh hai đối tượng TcpListener.
SVTH: Nguyễn Văn Xuân

Trang 10


Khóa luận tốt nghiệp

GVHD: Th.S Ngô Đình Thưởng

• GetHashCode(): Lấy hash code.
• GetType(): Lấy kiểu của thể hiện hiện tại.
• Panding(): Kiểm tra xem yêu cầu đang chờ kết nối hay không.
• Start(): Bắt đầu lắng nghe kết nối.
• Stop(): Ngừng lắng nghe kết nối.
• ToString(): Chuyển đối tượng TcpLisener thành chuỗi.
Sau khi đối tượng TcpClient được tạo ra, tất cả các truyền thông với thiết
bị ở xa đó được thực hiện với đối tượng TcpClient mới chứ không phải với
đối tượng TcpListener có thể chấp nhận kết nối khác. Để đóng đối tượng
TcpListener ta dùng phương thức Stop().
1.1.6.3. Lớp UDPClient:
Lớp UdpClient được tạo ra để giúp cho việc lập trình mạng với giao thức
UDP được đơn giản hơn. Lớp UdpClient có bốn phương thức tạo lập.
• UdpClient(): tạo ra một đối tượng UdpClient nhưng không gán vào địa
chỉ hay port nào.
• UdpClient(int port): Gán đối tượng UdpClient mới tạo vào một port.
• UdpClient(IPEndPoint iep): Gán đối tượng UdpClient mới tạo vào một

địa chỉ IP cục bộ và một port.
• UdpClient(string host, string port): Gán đối tượng UdpClient mới tạo
vào một địa chỉ IP và một port bất kỳ và kết hợp nó với một địa IP ở xa.
Các phương thức tạo lập của lớp UdpClient tương tự như các phương pháp
tạo lập của lớp TcpClient, chúng ta có thể cho hệ thống chọn port thích hợp
cho ứng dụng hoặc ta có thể chỉ ra port được dùng trong ứng dụng. Nếu ứng
dụng UDP phải chấp nhận dữ liệu trên một port nào đó, ta phải định nghĩa
port đó trong phương thức tạo lập của lớp UdpClient.
Phương thức:
• Close(): Đóng Socket ở bên dưới.
• Connect(): Cho phép chỉ ra IPEndPoint ở xa để gởi và nhận dữ liệu.
• DropMulticastGroup(): Gở bỏ Socket từ một nhóm UDP Multicast.
• Equals(): So sánh hai đối tượng UdpClient.
SVTH: Nguyễn Văn Xuân

Trang 11


Khóa luận tốt nghiệp

GVHD: Th.S Ngô Đình Thưởng

• GetHashCode(): Lấy hash code.
• GetType(): Lấy kiểu của đối tượng hiện tại.
• JoinMulticastGroup(): Thêm Socket vào một nhóm UDP Multicast.
• Receive(): Nhận dữ liệu từ Socket.
• Send(): Gởi dữ liệu đến thiết bị ở xa từ Socket.
• ToString(): Chuyển đối tượng UdpClient thành chuỗi.
1.2. Xử lý tiến trình trong lập trình đa luồng
1.2.1.


Khái niệm luồng

Một luồng (Thread) là một chuỗi liên tiếp những sự thực thi trong chương
trình. Trong một chương trình C#, việc thực thi bắt đầu bằng phương thức
main() và tiếp tục cho đến khi kết thúc hàm main(). Cấu trúc này rất hay cho
những chương trình có một chuỗi xác định những nhiệm vụ liên tiếp. Nhưng
thường thì một chương trình cần làm nhiều công việc hơn vào cùng một lúc.
Ví dụ trong Internet Explorer khi ta đang tải một trang web thì ta nhấn nút back
hay một link nào đó, để làm việc này Internet Explorer sẽ phải làm ít nhất là 3
việc:
• Lấy dữ liệu được trả về từ Internet cùng với các tập tin đi kèm.
• Thể hiện trang Web.
• Xem người dùng có nhập để làm thứ gì khác không.
Để đơn giản vấn đề này ta giả sử Internet Explorer chỉ làm hai công việc:
• Xem người dùng có nhập để làm thứ gì khác không.
• Xem người dùng có nhập gì không.
Để thực hành việc này ta sẽ viết một phương thức dùng để lấy và thể hiện
trang Web. Giả sử rằng việc trình bày trang Web mất nhiều thời gian (do phải
thi hành các đoạn javascript hay các hiệu ứng nào đó …). Vì vậy sau một
khoảng thời gian ngắn khoảng 1/12 giây, phương thức sẽ kiểm tra xem người
dùng có nhập gì không. Nếu có thì nó sẽ đuơc xử lí, nếu không thì việc trình
bày trang sẽ được tiếp tục. Và sau 1/12 giây việc kiểm tra sẽ được lặp lại. Tuy
nhiên viết phương thức này thì rất phức tạp do đó ta sẽ dùng kiến trúc event
trong Window nghĩa là khi việc nhập xảy ra hệ thống sẽ thông báo cho ứng
SVTH: Nguyễn Văn Xuân

Trang 12



Khóa luận tốt nghiệp

GVHD: Th.S Ngô Đình Thưởng

dụng bằng cách đưa ra một event. Ta sẽ cập nhật phương thức để cho phép dùng
các event:
• Ta sẽ viết một bộ xử lí event để đáp ứng đối với việc nhập của người
dùng.
• Ta sẽ viết một phương thức để lấy và trình bày dữ liệu. Phương thức
này được thực thi khi ta không làm bất cứ điều gì khác.
Ta hãy xem cách phương thức lấy và trình bày trang web làm việc: đầu tiên
nó sẽ tự định thời gian. Trong khi nó đang chạy, máy tính không thể đáp ứng
việc nhập của người dùng . Do đó nó phải chú ý đến việc định thời gian để gọi
phương thức kiểm tra việc nhập của người dùng, nghĩa là phương thức vừa
chạy vừa quan sát thời gian. Bên cạnh đó nó còn phải quan tâm đến việc lưu trữ
trạng thái trước khi nó gọi phương thức khác để sau khi phương thức khác
thực hiện xong nó sẽ trả về đúng chỗ nó đã dừng. Vào thời Window 3.1 đây
thực sự là những gì phải làm để xử lí tình huống này. Tuy nhiên ở NT3.1 và sau
đó là Windows 95 trở đi đã có việc xử lí đa luồng điều này làm việc giải quyết
vấn đề tiện lợi hơn. Dưới đây chúng ta sẽ tìm hiểu một vài lớp cơ bản trong
ngôn ngữ lập trình C# và vấn đề đồng bộ hóa (Synchronization) trong lập
trình đa luồng.
1.2.2.

Khảo sát namespace System.Threading

Namespace System.Threading cung cấp một số kiểu dữ liệu cho phép bạn
thực hiện lập trình đa luồng. Ngoài việc cung cấp những kiểu dữ liệu tượng
trưng cho một luồng cụ thể nào đó, namespace này còn định nghĩa những lớp
có thể quản lý một collection các luồng (ThreadPool), một lớp Timer đơn

giản (không dựa vào GUI) và các lớp cung cấp truy cập được đồng bộ vào dữ
liệu được chia sẽ sử dụng.

SVTH: Nguyễn Văn Xuân

Trang 13


Khóa luận tốt nghiệp

GVHD: Th.S Ngô Đình Thưởng

Một số lớp của namespace System.Threading:
Các lớp thành viên

Mô tả

Interlocked

Lớp này dùng cung cấp truy cập đồng bộ hóa vào dữ
liệu được chia sẽ sử dụng (shared data).
Lớp này cung cấp việc đồng bộ hóa các đối tượng luồng

Moniter

sử dụng khóa chốt (lock) và tín hiệu chờ (wait signal).
Lớp này cung cấp việc đồng bộ hóa sơ đẳng có thể

Mutex


được dùng đối với inter process synchronization.
Lớp này tượng trưng cho một luồng được thi hành trong

Thread

lòng Common Language Runtime. Sử dụng lớp này bạn
có khả năng bổ sung những luồng khác trong cùng
AppDomain.
Lớp này quản lý những luồng có liên hệ với nhau trong

ThreadPool

cùng một Process nào đó.
Cho biết một delegate có thể được triệu gọi vào một lúc

Timer

được khai báo nào đó. Tác vụ wait được thi hành bởi
luồng trong thread pool.
Lớp này tượng trưng cho tất cả các đối tượng đồng bộ

WaitHandle

hóa (cho phép multiple wait) vào lúc chạy.
ThreadStart

Lớp này là một delegate chỉ về hàm hành sự nào đó

TimerCallBack


phải được thi hành đầu tiên khi một luồng bắt đầu.
Delegate đối với Timer.

WaitCallBack

Lớp này là một delegate định nghĩa hàm hành sự kêu
gọi lại (callback) đối với ThreadPool user work item.

Lớp

đơn

giản

nhất

trong

tất

cả

các

lớp

thuộc

Namespace


System.Threading là lớp Thread. Lớp này tượng trưng cho một vỏ bọc hướng
đối tượng bao quanh một lộ trình thi hành trong lòng một AppDomain nào đó.
Lớp này định nghĩa một số hàm thực thi (cả static lẫn shared) cho phép bạn tạo
mới những luồng từ luồng hiện hành, cũng như cho Sleep, Stop hay Kill một
luồng nào đó.

SVTH: Nguyễn Văn Xuân

Trang 14


Khóa luận tốt nghiệp

GVHD: Th.S Ngô Đình Thưởng

Các thành phần static của lớp Thread:
Các thành phần Static

Mô tả

CurrentThread

Thuộc tính read-only này trả về một quy chiếu về
luồng hiện đang chạy.

GetData()

Đi lấy vị trí từ slot được khai báo trên luồng hiện
hành đối với domain hiện hành trong luồng.


SetData()

Cho đặt để trị lên slot được khai báo trên luồng hiện

GetDomain()

hành đối với domain hiện hành trong luồng
Đi lấy một qui chiếu về AppDomain hiện hành

GetDomainID()

(hoặc mã nhận diện ID của domain này) mà luồng
hiện đang chạy trên đó.

Sleep()

Cho ngưng luồng hiện hành trong một thời gian nhất
định được khai báo.

Ngoài ra lớp Thread cũng hổ trợ các thành viên cấp đối tượng.
Các lớp thành viên
IsAlive

Mô tả
Thuộc tính này trả về một trị boolean cho biết liệu xem
luồng đã khởi đông hay chưa.

IsBackground

Đi lấy hoặc đặt để giá trị cho biết liệu xem luồng là một

luồng nền hay không.

Name

Thuộc tính này cho phép bạn thiết lập một tên văn bản

Priority

mang
vớicủa
luồng.
Đi lấytính
hoặcthân
đặtthiện
để ưuđối
tiên
một luồng. Có thể được
gán một trị lấy từ enumeration ThreadPriority (chẳng
hạn

Normal,

Lowest,

Highest,

BelowNormal,

AboveNormal).
ThreadState


Đi lấy hoặc đặt để tình trạng của luồng. Có thế được
gán từ enumeration ThreadState (chẳng hạn
Unstarted, Running, WaitSleepJoin, Suspended,

Interrup()

SuspendRequested,
AbortRequested,
Stopped).
Cho ngưng chạy luồng
hiện hành.

Join()

Yêu cầu luồng chờ đối với luồng bị ngưng chạy.

Resume()

Tiếp tục lại đối với một luồng bị ngưng chạy.

SVTH: Nguyễn Văn Xuân

Trang 15


Khóa luận tốt nghiệp

GVHD: Th.S Ngô Đình Thưởng


Start()

Cho bắt đầu thi hành luồng được khai báo bởi delegate

Suspend()

ThreadStart.
Cho ngưng chạy một luồng. Nếu luồng đã bị ngưng rồi,

Abort()

một triệu gọi hàm Suspend() sẽ không có tác dụng.
Kết thúc một tiểu trình bằng cách nén ngoại lệ
System.Threading.ThreadAbortException

trong



lệnh đang được chạy.
Mã lệnh của tiểu trình bị hủy có thể tắt ngoại lệ
ThreadAbortException để thực hiện việc dọn dẹp,
nhưng bộ thực thi sẽ tự động nén ngoại lệ này lần nữa
1.3. Đồng bộ và bất đồng bộ trong lập trình đa luồng
Đôi khi có thể bạn muốn điều khiển việc truy cập vào một nguồn lực, chẳng
hạn các thuộc tính hoặc các hàm của một đối tượng, làm thế nào chỉ một
mạch trình được phép thay đổi hoặc sử dụng nguồn lực đó mà thôi. Việc đồng
bộ hóa được thể hiện thông qua một cái khóa được thiết lập trên đối tượng,
ngăn không cho luồng nào đó truy cập khi mạch trình đi trước chưa xong công
việc.

Trong phần này, ta sẽ là quen với cơ chế đồng bộ hóa mà Common
Language Runtime cung cấp: lệnh lock. Nhưng trước tiên, ta cần mô phỏng
một nguồn lực được chia sẽ sử dụng bằng cách sử dụng một biến số nguyên
đơn giản counter.
Để bắt đầu, ta khai báo biến thành viên và khởi gán về zero:
int counter = 0;

Bài toán được đặt ra ở đây như sau: Luồng thứ nhất sẽ đọc trị counter (0)
rồi gán giá trị này cho biến trung gian (temp). Tiếp đó tăng trị của temp rồi
Sleep một khoảng thời gian. Luồng thứ nhất xong việc thì gán trị của temp trả
về cho counter và cho hiển thị trị này. Trong khi nó làm công việc, thì luồng thứ
hai cũng thực hiện một công việc giống như vậy. Ta cho việc này lập này
khoảng 1000 lần. Kết quả mà ta chờ đợi là hai luồng trên đếm lần lượt tăng
biến counter lên 1 và in ra kết quả 1,2, 3, 4 … tuy nhiên ta sẽ xét đoạn chương
trình dưới đây và thấy rằng kết quả hoàn toàn khác với những gì mà chúng ta
mong đợi.
SVTH: Nguyễn Văn Xuân

Trang 16


Khóa luận tốt nghiệp

GVHD: Th.S Ngô Đình Thưởng

using System;
using System.Threading;
namespace TestThread
{
public class Tester

{
private int counter = 0;
static void Main(string[] args)
{
Tester t = new Tester(); t.DoTest();
Console.ReadLine();
}
public void DoTest()
{
Thread t1 = new Thread(new ThreadStart(Incrementer));
t1.IsBackground

=

true;

t1.Name

=

"Thread

One";

t1.Start();
Console.WriteLine("Start thread {0}", t1.Name);
Thread t2 = new Thread(new ThreadStart(Incrementer));
t2.IsBackground = true;
t2.Name = "Thread Two"; t2.Start();
Console.WriteLine("Start thread {0}", t2.Name);

t1.Join();
t2.Join();
Console.WriteLine("All my threads are done.");
}
public void Incrementer()
{
try
{
while (counter < 1000)
{
nt temp = counter; temp++;
Thread.Sleep(1); counter = temp;
Console.WriteLine("Thread {0}.
Incrementer: {1}",
Thread.CurrentThread.Name, counter);

SVTH: Nguyễn Văn Xuân

Trang 17


Khóa luận tốt nghiệp

GVHD: Th.S Ngô Đình Thưởng
}
}
catch (ThreadInterruptedException)
{
Console.WriteLine("Thread {0} interrupted!
Cleaning up...", Thread.CurrentThread.Name);

}
finally
{
Console.WriteLine("Thread {0} Existing.",
Thread.CurrentThread.Name);
}
}

}
}

Kết quả đạt được là :

Hình 1.3 Kết quả chương trình đồng bộ hóa
Do đó ta cần phải đồng bộ hóa việc truy cập đối tượng counter. C# cung cấp
đối tượng Lock để thưc hiện công việc đồng bộ hóa này. Một lock sẽ đánh
dấu một critical section trên đoạn mã đồng thời cung cấp việc đồng bộ hóa đối
với đối tượng được chỉ định khi lock có hiệu lực. Cú pháp sử dụng một Lock
yêu cầu khóa chặt một đối tượng rồi thi hành một câu lệnh hoặc một khối lệnh
rồi sẽ mở khóa ở cuối câu hoặc khối lệnh đó. C# cung cấp hổ trợ trực tiếp
khóa chặt thông qua từ chốt lock. Ta sẽ tra qua theo một đối tượng qui chiếu
và theo sau từ chốt là một khối lệnh.
lock(expression) statement-block

SVTH: Nguyễn Văn Xuân

Trang 18


Khóa luận tốt nghiệp


GVHD: Th.S Ngô Đình Thưởng

Trong ví dụ trên, để có được kết quả như mong muốn, ta sẽ sửa hàm
Incrementer lại như sau:
try
{
lock (this)
{
while (counter < 1000)
{
int temp = counter;
temp++;
Thread.Sleep(1);
counter = temp;
Console.WriteLine("Thread {0}. Incrementer: {1}",
Thread.CurrentThread.Name, counter);
}
}
}

Kết quả thu được sẽ là:

Hình 1.4 Kết quả chương trình bất đồng bộ
1.4.

Hệ mã hóa công khai RSA

1.4.1.


Khái niệm mã hóa

Trong mọi lĩnh vực kinh tế, chính trị, xã hội, quân sự… luôn có nhu cầu
trao đổi thông tin giữa các cá nhân, các công ty, tổ chức, hoặc giữa các quốc
gia với nhau. Ngày nay, với sự phát triển của công nghệ thông tin đặt biệt là
mạng internet thì việc truyền tải thông tin đã dể dàng và nhanh chóng hơn.

SVTH: Nguyễn Văn Xuân

Trang 19


Khóa luận tốt nghiệp

GVHD: Th.S Ngô Đình Thưởng

Hình 1.5 Mã hóa
Và vấn đề đặt ra là tính bảo mật trong quá trình truyền tải thông tin, đặt
biệt quan trọng đối với những thông tin liên quan đến chính trị, quân sự, hợp
đồng kinh tế… Vì vậy nghành khoa học nghiên cứu vế mã hóa thông tin được
phát triển. Việc mã hóa là làm cho thông tin biến sang một dạng khác khi đó chỉ
có bên gửi và bên nhận mới đọc được, còn người ngoài dù nhận được thông tin
nhưng cũng không thể hiểu được nôi dung.

Hình 1.6 Mã hóa và giải mã thông tin được truyền đi.
Như chúng ta thấy ở mô hình 1.5 : Việc trao đổi thông tin được thực hiện
qua các bước sau:
• Tạo ra thông tin cần gởi đi.
• Gởi thông tin này cho đối tác.
Ở mô hình 1.6: Việc trao đổi thông tin được thực hiện:

• Tạo thông tin cần gởi.
• Mã hóa và gởi thông tin đã được mã hóa đi.
• Đối tác nhận và giải mã thông tin.
• Đối tác có được thông tin ban đầu của người gởi.
Với 2 thao tác mã hóa và giải mã ta đã đảm bảo thông tin được gửi an toàn
và chính xác.
Chúng ta có nhiều phương pháp để mã hóa thông tin: Ở đây ta tìm hiểu về
hệ mã hóa công khai RSA.

SVTH: Nguyễn Văn Xuân

Trang 20


Khóa luận tốt nghiệp
1.4.2.

GVHD: Th.S Ngô Đình Thưởng

Hệ mã khóa

Mã khóa bí mật: thông tin sẻ được mã hóa theo một phương pháp ứng với
một key, key này dùng để lập mã và đồng thời cũng để giải mã. Vì vậy key
phải được giữ bí mật, chỉ có người lập mã và người nhận biết được, nếu key
bị lộ thì người ngoài sẽ dể dàng giải mã và đọc được thông tin.

Hình 1.7 Mã hóa bí mật
Mã khóa công khai: sử dụng 2 key public key- private key.
Public key: Được sử dụng để mã hoá những thông tin mà ta muốn chia sẻ
với bất cứ ai. Chính vì vậy ta có thể tự do phân phát nó cho bất cứ ai mà ta cần

chia sẻ thông tin ở dạng mã hoá.
Private key: Đúng như cái tên, Key này thuộc sở hữu riêng tư của bạn(ứng
với public key) và nó được sử dụng để giải mã thông tin. Chỉ mình bạn sở hữu
nó, Key này không được phép và không nên phân phát cho bất cứ ai.
Nghĩa là mỗi người sẽ giữ 2 key 1 dùng để mã hóa key này được công bố
rộng rãi, 1 dùng để giải mã key này giữ kín.
Khi ai đó có nhu cầu trao đổi thông tin với bạn, sẽ dùng public key mà bạn
công bố để mã hóa thông tin và gửi cho bạn, khi nhận được bạn dùng private
key để giải mã. Những người khác dù có nhận được thông tin nhưng không
biết được private key thì cũng không thể giải mã và đọc được thông tin.

Hình 1.8 Mã hóa công khai

SVTH: Nguyễn Văn Xuân

Trang 21


Khóa luận tốt nghiệp
1.4.3.

GVHD: Th.S Ngô Đình Thưởng

Thuật toán mã hóa RSA

Thuật toán RSA có hai khóa: Khóa công khai (hay khóa công cộng) và
khóa bí mật (hay khóa cá nhân). Mỗi khóa là những số cố định sử dụng trong
quá trình mã hóa và giải mã. Khóa công khai được công bố rộng rãi cho mọi
người và được dùng để mã hóa. Những thông tin được mã hóa bằng khóa công
khai chỉ có thể được giải mã bằng khóa bí mật tương ứng. Nói cách khác, mọi

người đều có thể mã hóa nhưng chỉ có người biết khóa cá nhân (bí mật) mới có
thể giải mã được.
Ta có thể mô phỏng trực quan một hệ mật mã khoá công khai như sau :
B muốn gửi cho A một thông tin mật mà B muốn duy nhất A có thể đọc
được. Để làm được điều này, A gửi cho B một chiếc hộp có khóa đã mở sẵn và
giữ lại chìa khóa. B nhận chiếc hộp, cho vào đó một tờ giấy viết thư bình
thường và khóa lại (như loại khoá thông thường chỉ cần sập chốt lại, sau khi
sập chốt khóa ngay cả B cũng không thể mở lại được-không đọc lại hay sửa
thông tin trong thư được nữa). Sau đó B gửi chiếc hộp lại cho A. A mở hộp với
chìa khóa của mình và đọc thông tin trong thư. Trong ví dụ này, chiếc hộp với
khóa mở đóng vai trò khóa công khai, chiếc chìa khóa chính là khóa bí mật.
Tạo khóa:
Giả sử A và B cần trao đổi thông tin bí mật thông qua một kênh không an
toàn (ví dụ như Internet). Với thuật toán RSA, A đầu tiên cần tạo ra cho mình
cặp khóa gồm khóa công khai và khóa bí mật theo các bước sau:
a) Chọn 2 số nguyên tố lớn p và q với p≠q , lựa chọn ngẫu nhiên và độc
lập.
b) Tính: n=pq.
c) Tính: giá trị hàm số: φ (n)=(p-1)(q-1).
d) Chọn một số tự nhiên e sao cho 1với φ (n) . Công bố (n,e).
e) Tính: d sao cho de≡ 1(mod φ (n)).
Một số lưu ý:
• Các số nguyên tố thường được chọn bằng phương pháp thử xác suất.
• Các bước 4 và 5 có thể được thực hiện bằng giải thuật Euclide mở rộng.

SVTH: Nguyễn Văn Xuân

Trang 22



×