LẬP TRÌNH MẠNG VỚI CÁC LỚP UDP VÀ TCP
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. (ví dụ trên có 2 ứng dụng trong máy A muốn trao đổi với với 2 ứng dụng trên máy
B)
Bài giảng số 11
LẬP TRÌNH MẠNG VỚI CÁC LỚP UDP VÀ TCP
Mục tiêu của bài giảng: Sau khi kết thúc bài học sinh viên có thể
Trình bày được chức năng của các lớp Socket, UDP, TCP (TCPClient &
TCPListener) và các lớp IPAddress, IPHostEntry, IPEndpoint trong lập
trình mạng.
Khai báo và sử dụng được các lớp UDP, TCP
Vận dụng các lớp UDP, TCP để viết một số ứng dụng Client và Server đơn
giản như Chat, Ping, Telnet, Server …
Nội dung:
1. Khái niệm Địa chỉ và cổng (Address & Port)
Port Port
1 1
…
…
101001010
100 100
A: 192.168.1.1 B: 192.168.1.2
- 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. (ví dụ trên có 2 ứng dụng trong máy A muốn trao đổi vớ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)
Biªn so¹n : NguyÔn Minh Quý – Khoa CNTT - §HSPKTHY 11/2006 1
? 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?
Giải quyết: Mỗi ứng dụng trên máy B sẽ được gán một số hiệu (mà ta vẫn quen 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 chỉ 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ì (vì không phải là của mình).
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ỉ (Address) và số hiệu cổng (Port) của ứng dụng kia.
+ Hai ứng dụng có thể cùng nằm trên một máy
+ Hai ứng dụng trên cùng một máy không được trùng số hiệu cổng.
+ LocalHost : (Địa chỉ máy hiện đang chạy ứng dụng):, V ới B: LocalHost =
192.168.1.2, với A thì Localhost = 192.168.1.1;
+ RemoteHost (Địa chỉ của máy chạy ứng dụng đang tham gia trao đổi thông tin v ới
ứng dụng hiện tại). RemoteHost của ứng dụng chạy trên máy A là : 192.168.1.2;
RemoteHost của ứng dụng chạy trên máy B là : 192.168.1.1;
+ LocalPort: LocalPort của ứng dụng chạy trên máy A (FTP) là 100, c ủa ứng d ụng
chạy trên máy B (FTP) là 5;
+ RemotePort: RemotePort của ứng dụng chạy trên máy A (FTP) là 5, của ứng d ụng
chạy trên máy B (FTP) là 100;
+ Hai ứng dụng đặt trên hay máy khác nhau thì LocalPort có th ể gi ống nhau (Nh ưng
nếu đặt trên một máy thì không được trùng nhau)
2. Lớp IPAddress
2.1 Giới thiệu
Trên Internet mỗi một trạm (có thể là máy tính, máy in, thi ết bị …) đ ều có m ột đ ịnh danh
duy nhất, định danh đó thường được gọi là m ột địa ch ỉ (Address). Đ ịa ch ỉ trên Internet là
một tập hợp gồm 4 con số có giá trị từ 0-255 và cách nhau bởi dấu chấm.
Để thể hiện địa chỉ này, người ta có thể viết dưới các dạng sau:
- Tên : ví dụ May01, Server, ….
- Địa chỉ IP nhưng đặt trong một xâu: ", "127.0.0.1"
- Đặt trong một mảng 4 byte, mỗi byte chứa m ột số từ 0-255. Ví d ụ đ ể bi ểu
diễn địa chỉ 192.168.1.1 ta có thể viết:
Dim DiaChi(3) as Byte"192.168.1.1
DiaChi(0) = 192
DiaChi(1) = 168
DiaChi(2) = 1
DiaChi(3) = 1
- Hoặc cũng có thể là một số (long), có độ dài 4 byte. Ví dụ, với địa chỉ
192.168.1.1 ở trên thì giá trị đó sẽ là: 16885952 (đây là số ở hệ thập phân khi
xếp liền 4 byte ở trên lại với nhau 00000001 00000001 10101000 11000000
1 (Byte 0) 1 168 192 (Byte 3)
Như vậy, để đổi một địa chỉ chuẩn ra dạng số ta chỉ việc tính toán cho t ừng thành
phần. Ví dụ: Đổi địa chỉ 192.168.1.2 ra số, ta tính như sau :
2 * 256 ^ 3 + 1* 256 ^ 2 + 168 * 256 ^ 1 + 192 * 256 ^ 0
Biªn so¹n : NguyÔn Minh Quý – Khoa CNTT - §HSPKTHY 11/2006 2
Trong MS.NET, IPAddress là một lớp dùng để mô tả địa chỉ này. Đây là l ớp rất c ơ b ản
được sử dụng khi chúng ta thao tác (truyền) vào các lớp như IPEndpoint, UDP, TCP,
Socket …
2.2 Các thành viên của lớp
Phạm
Name Description
vi
Cung cấp một địa chỉ IP (thường là 0.0.0.0) để chỉ ra
rằng Server phải lắng nghe các hoạt động của Client
Any
trên tất cả các Card mạng (sử dụng khi xây dựng
Server). Thuộc tính này chỉ đọc.
Cung cấp một địa chỉ IP quảng bá (Broadcast, thường
là 255.255.255.255), ở dạng số Long. Muốn lấy ở
Broadcast
dạng xâu, viết: Broadcast.ToString().
This field is read-only.
Trả về một địa chỉ IP lặp (IP Loopback, ví dụ
Loopback
127.0.0.1). This field is read-only.
Một địa chỉ IP (An Internet Protocol (IP) address) ở
dạng số Long. (Muốn chuyển sang dạng dấu chấm,
Address
viết : Address.ToString(). (Khong con su dung trong
phien ban moi !!!!!!
Trả về họ địa chỉ của địa chỉ IP hiện hành. Nếu địa chỉ
AddressFamily ở dạng IPv4 thì kết quả là Internetwork, và
InternetworkV6 nếu là địa chỉ IPv6.
P/Vi Method Name Description
- IPAddress(Số_Long) As IPAddress
Tạo địa chỉ IP từ một số long
k/tạo Constructor
- IPAddress(Mảng_Byte) Tạo địa chỉ IP
từ một mảng byte (4 byte).
GetAddressBytes as
Chuyển địa chỉ thành mảng byte (4 byte).
bytes()
Đảo thứ tự byte của một số cho đúng với thứ tự byte
HostToNetworkOrder
trong địa chỉ IPAddress.
IsLoopback Cho biết địa chỉ có phải là địa chỉ lặp hay không?
Đảo thứ tự byte của một địa chỉ cho đúng với thứ tự
NetworkToHostOrder
byte thông thường.
Chuyển một địa chỉ IP ở dạng xâu thành một địa chỉ IP
Parse
chuẩn (Một đối tượng IPAddress)
Trả về địa chỉ IP (một xâu) nhưng ở dạng ký pháp có
ToString as String
dấu chấm. (Ví dụ "192.168.1.1").
TryParse (Địa_ChỉIP: Kiểm tra xem một địa chỉ IP (ở dạng xâu) có phải đúng
String) là địa chỉ IP hợp lệ hay không ? True = đúng
2.3 Ví dụ
a) Tạo một địa chỉ IP (Tạo một đối tượng IPAddress) có giá trị là 16885952
Biªn so¹n : NguyÔn Minh Quý – Khoa CNTT - §HSPKTHY 11/2006 3
00000001 00000001 10101000 11000000
b) Tạo một địa chỉ IP từ một mảng byte tương ứng với địa chỉ 192.168.10.10
c) Tạo một địa chỉ IP từ một xâu.
d) Tạo một địa chỉ 192.168.1.2
Imports System.Net
Public Class Form1
Private Sub TaoDiaChi()
Dim b(3) As Byte
b(0) = 192
b(1) = 168
b(2) = 10
b(3) = 10
'/// Tạo địa chỉ từ các hàm khởi tạo
Dim Ip1 As New IPAddress(b) '//Tạo địa chỉ từ mảng byte ở trên
Dim Ip2 As New IPAddress(16885952)
Dim Ip3 As IPAddress=IPAddress.Parse("172.16.1.1")
MsgBox(Ip1.ToString)
MsgBox(Ip2.ToString)
MsgBox(Ip3.ToString)
'/// Tạo địa chỉ thông qua việc tính toán.
Dim So As Long = 192* 256^0+168* 256^1+1* 256^2 + 2*256^3
Dim Ip4 As New IPAddress(So)
Msgbox Ip4.ToString()
End Sub
End Class
e) Kiểm tra xem 192.168.1.300 có phải là địa chỉ IP hợp lệ không ?
Private Sub KiemTra()
Dim Ip4 As string = "127.0.0.1"
Dim Ip5 As String = "999.0.0.1"
MsgBox(IPAddress.TryParse(Ip4, New IPAddress(1)))
MsgBox(IPAddress.TryParse(Ip5, New IPAddress(1)))
End Sub
*** Lưu ý: Tham số thứ hai là một đối tượng bất kỳ thuộc ki ểu IPAddress, do v ậy b ạn có
thể viết New IPAddress(0), IPAddress(1),…
f) Chuyển địa chỉ hiện hành ra mảng byte và hiển thị từng thành phần trong mảng đó
Sub ChuyenDoi()
Dim Ip3 As New IPAddress(16885952)
Dim b() As Byte
b = Ip3.GetAddressBytes()
MsgBox("Address: " & b(0) &"." & b(1) &"." & b(2) & "." & b(3))
Biªn so¹n : NguyÔn Minh Quý – Khoa CNTT - §HSPKTHY 11/2006 4
End Sub
3. Lớp IPEndpoint
3.1 Giới thiệu
Trong mạng, để hai trạm có thể trao đổi thông tin được với nhau thì chúng c ần ph ải bi ết
được địa chỉ (IP) của nhau và số hiệu cổng mà hai bên dùng để trao đ ổi thông tin. Lớp
IPAddress mới chỉ cung cấp cho ta một vế là địa chỉ IP (IPAddress ), còn thiếu vế thứ hai là
số hiệu cổng (Port number). Như vậy, lớp IPEndpoint chính là lớp chứa đựng c ả
IPAddress và Port number.
Đối tượng IPEndpoint sẽ được dùng sau này để truyền trực ti ếp cho các đ ối t ượng UDP,
TCP…
3.2 Các thành viên của lớp
Hàm khởi tạo
IPEndPoint (Int64, Int32)
Tạo một đối tượng mới của lớp IPEndPoint, tham số
truyền vào là địa chỉ IP (ở dạng số) và cổng sẽ dùng để
giao tiếp.
IPEndPoint (IPAddress,
Int32) Tạo một đối tượng mới của lớp IPEndPoint, Tham số
truyền vào là một địa chỉ IPAddress và số hiệu cổng dùng
để giao tiếp. (Tham khảo cách tạo IPAddress ở phần trên)
P/Vi Thuộc tính Description
Address Trả về hoặc thiết lập địa chỉ IP cho endpoint. (Trả về một
đối tượng IPAddress)
AddressFamily Lấy về loại giao thức mà Endpoint này đang sử dụng.
Port Gets or sets số hiệu cổng của endpoint.
P/Vi Phương thức Description
Create Tạo một endpoint từ một địa chỉ socket (socket address).
ToString Trả về địa chỉ IP và số hiệu cổng theo khuôn dạng ĐịaChỉ:
Cổng, ví dụ: “192.168.1.1:8080”
3.3 Ví dụ
Tạo một đối tượng IPEndpoint có địa chỉ là "127.0.0.1", cổng là 1000
Để tạo một IPEndpoint, ta có thể dùng 2 hàm thiết lập, trong đó có m ột hàm thi ết l ập đòi
hỏi phải truyền một đối tượng IPAddress vào. Khi đó chúng ta c ần ph ải t ạo đ ối t ượng
IPAddress trước theo các cách như đã đề cập trong phần 1.
Private Sub TaoEndpoint()
'/// Tạo một địa chỉ IP
Dim IPAdd As IPAddress = IPAddress.Parse("127.0.0.1")
Biªn so¹n : NguyÔn Minh Quý – Khoa CNTT - §HSPKTHY 11/2006 5
'/// Truyền vào cho hàm khởi tạo để tạo IPEndpoint
Dim IPep As New IPEndPoint(IPAdd, 1000)
MsgBox(IPep.ToString)
End Sub
Tạo một EndPoint từ tên máy: Ta cũng có thể tạo đối tượng IPAddress t ừ tên c ủa máy
thông qua phương thức tĩnh DNS.GetHostAddresses của lớp DNS. Sau đó truyền đ ối
tượng IP này vào cho phương thức khởi tạo của IPEndPoint để tạo đối tượng IPEndpoint
mới.
Private Sub TaoEndPointBoiTenMay()
Dim IPAdd As IPAddress
IPAdd = Dns.GetHostAddresses("Localhost")(0)
Dim IPep As New IPEndPoint(IPAdd, 1000)
MsgBox(IPep.ToString)
End Sub
*** Lưu ý : Vì một máy tính có thể có nhiều Card mạng (Interface) do vậy có thể có
nhiều hơn 1 địa chỉ IP. Hàm GetHostAddresses sẽ trả về cho ta một mảng chứa tất cả
các địa chỉ đó. Ta truyền giá trị 0 để lấy địa chỉ của Card mạng đầu tiên.
4. Lớp IPHostEntry
4.1 Giới thiệu
IPHostEntry là lớp chứa (Container) về thông tin địa chỉ của các máy trạm trên Internet.
Lưu ý: Nó chỉ là nơi để "chứa" , do vậy trước khi sử dụng c ần phải "N ạp" thông tin vào
cho nó.
Lớp này rất hay được dùng với lớp DNS
4.2 Các thành viên của lớp
Public Properties
Name Description
AddressList Gets or sets a list of IP addresses that are associated with a
host.
Aliases Gets or sets a list of aliases that are associated with a host.
HostName Gets or sets the DNS name of the host.
4.3 Ví dụ
……
5. Lớp DNS
5.1 Giới thiệu
Biªn so¹n : NguyÔn Minh Quý – Khoa CNTT - §HSPKTHY 11/2006 6
DNS (Domain Name Service) là một lớp giúp chúng ta trong vi ệc phân gi ải tên mi ền
(Domain Resolution) đơn giản. (Phân giải tên miền tức là : Đầu vào là Tên c ủa máy trạm,
ví dụ ServerCNTT thì đầu ra sẽ cho ta địa chỉ IP tương ứng của máy đó, ví dụ 192.168.3.8)
Ngoài ra lớp Dns còn có rất nhiều phương thức cho ta thêm thông tin v ề máy c ục b ộ nh ư
tên, địa chỉ v.v…
5.2 Các thành viên của lớp
Name Description
GetHostByAddress (IP As Trả về thông tin (IPHostEntry) của trạm
String) có địa chỉ IP được truyền vào.
GetHostByAddress (IP As
IPAddress) As IPHostEntry Thay bằng GetHostEntry()
GetHostByName (Tên trạm: Trả về thông tin (IPHostEntry) DNS của
String) As IPHostEntry một trạm . Đã bị loại bỏ. Thay bằng
GetHostEntry()
Thuộc tính HostName Cho ta biết tên của máy vừa được
phân giải. Nếu không phân giải
được thì có giá trị là địa chỉ IP.
GetHostAddresses Trả về tất cả các địa chỉ IP của
(IP_Or_HostName: String) một trạm.
as IPAddress()
GetHostEntry Giải đáp tên hoặc địa chỉ IP truyền
(IP_Or_HostName As vào và trả về một đối tượng
String) as IPHostEntry IPHostEntry tương ứng.
GetHostEntry (IP As
IPAddress)
GetHostName As String Lấy về tên của máy tính cục bộ.
Resolve (Hostname: String) Chuyển tên của máy hoặc địa chỉ IP
thành IPHostEntry tương ứng. Đã bị
bỏ !, Thay bằng GetHostEntry()
*** Lưu ý: Đây là các phương thức tĩnh, do vậy khi gọi thì gọi trực tiếp từ tên lớp
mà không cần phải khai báo một đối tượng mới của lớp này. Ví d ụ ta gọi: DNS.Resolve,
Dns.GetHostname, Dns.GetHostEntry v.v…
5.3 Ví dụ
a. Hiển thị tên của máy tính hiện tại
MsgBox(Dns.GetHostName())
b. Hiển thị tất cả địa chỉ IP của một máy nào đó.
Private Sub ShowIPs()
Dim ip As IPAddress
Biªn so¹n : NguyÔn Minh Quý – Khoa CNTT - §HSPKTHY 11/2006 7
Dim add() As IPAddress
Dim i As Integer
'/// Lấy tất cả địa chỉ IP của máy Notebook. (Một máy có thể có nhiều IP)
add = Dns.GetHostAddresses("notebook")
'/// Duyệt sử dụng For Each… (tập hợp)
For Each ip In add
MsgBox(ip.ToString)
Next
'/// Or Duyệt theo kiểu mảng
For i = 0 To add.Length - 1
MsgBox(add(i).ToString)
Next
End Sub
c. Tạo một IPHostEntry từ máy có tên là "Notebook"
d. Tạo một IPHostEntry từ địa chỉ "127.0.0.1"
e. Tạo một IPHostEntry từ một đối tượng IPAddress, có địa chỉ IP là 127.0.0.1
Private Sub CreatIPHostEntry()
Dim iphe1, iphe2, iphe3 As IPHostEntry
Dim ipadd As IPAddress = IPAddress.Parse("127.0.0.1")
iphe1 = Dns.GetHostEntry("Notebook ")
iphe2 = Dns.GetHostEntry("127.0.0.1")
iphe3 = Dns.GetHostEntry(ipadd)
MsgBox(iphe1.HostName) '/// Notebook (tùy vào máy)
MsgBox(iphe2.HostName) '/// Notebook
MsgBox(iphe3.HostName) '/// Notebook
End Sub
*** Lưu ý: Đối tượng IPHostEntry chúng ta tạo ở trên sẽ đ ược dùng r ất nhi ều trong các
phần sau của bài giảng này.
6. Lớp UDP
6.1 Giới thiệu
Giao thức UDP (User Datagram Protocol hay User Define Protocol) là m ột giao th ức phi
kết nối (Connectionless) có nghĩa là một bên có thể gửi dữ li ệu cho bên kia mà không c ần
biết là bên đó đã sẵn sàng hay chưa ? (Nói cách khác là không c ần thi ết l ập k ết n ối gi ữa
hai bên khi tiến hành trao đổi thông tin). Giao thức này không tin c ậy bằng giao th ức TCP
nhưng tốc độ lại nhanh và dễ cài đặt. Ngoài ra, với giao th ức UDP ta còn có th ể g ửi các
gói tin quảng bá (Broadcast) cho đồng thời nhiều máy.
Trong .NET, lớp UDPClient (nằm trong System.Net.Sockets) đóng gói các chức năng của
giao thức UDP.
Biªn so¹n : NguyÔn Minh Quý – Khoa CNTT - §HSPKTHY 11/2006 8
6.2 Các thành viên của lớp UDPClient
Constructor methods Description
UdpClient ()
Tạo một đối tượng (thể hiện) mới của lớp
UDPClient.
UdpClient (AddressFamily)
Tạo một đối tượng (thể hiện) mới của lớp
UDPClient. Thuộc một dòng địa chỉ
(AddressFamily) được chỉ định.
UdpClient (LocalPort: Int32)
Tạo một UdpClient và gắn (bind) một cổng cho
nó.
UdpClient (IPEndPoint)
Tạo một UdpClient và gắn (bind) một
IPEndpoint (gán địa chỉ IP và cổng) cho nó.
UdpClient (Int32, AddressFamily)
Tạo một UdpClient và gán số hiệu cổng,
AddressFamily
UdpClient (Remotehost: String, Int32)
Tạo một UdpClient và thiết lập với một trạm từ
xa mặc định.
PUBLIC Method
Name Description
BeginReceive Nhận dữ liệu Không đồng bộ từ máy ở xa.
BeginSend Gửi không đồng bộ dữ liệu tới máy ở xa
Close Đóng kết nối.
Connect Thiết lập một Default remote host.
EndReceive Kết thúc nhận dữ liệu không đồng bộ ở trên
EndSend Kết thúc việc gửi dữ liệu không đồng bộ ở trên
Receive Nhận dữ liệu (đồng bộ) do máy ở xa gửi. (Đồng bộ có
(EndPoint của nghĩa là các lệnh ngay sau lệnh Receive chỉ được thực thi
máy ở xa) As nếu Receive đã nhận được dữ liệu về . Còn nếu nó chưa
Byte() nhận được – dù chỉ một chút – thì nó vẫn cứ chờ (blocking))
Send Gửi dữ liệu (đồng bộ) cho máy ở xa.
Name Description
Biªn so¹n : NguyÔn Minh Quý – Khoa CNTT - §HSPKTHY 11/2006 9
UdpClient.Send (Byte[], Int32) Sends a UDP datagram to a remote host.
Supported by the .NET Compact Framework.
UdpClient.Send (Byte[], Int32, Sends a UDP datagram to the host at the
IPEndPoint) specified remote endpoint.
Supported by the .NET Compact Framework.
UdpClient.Send (Byte[], Int32, Sends a UDP datagram to a specified port on a
String, Int32) specified remote host.
Supported by the .NET Compact Framework.
- đồng bộ : Synchronous
- Không đồng bộ : Asynchronous
6.3 Ví dụ
Chuyển đổi một xâu ký tự sang mảng byte:
Dim Msg() As Byte
Msg = System.Text.Encoding.UTF8.GetBytes("Xin chao !")
Chuyển đổi mảng byte sang xâu ký tự:
S = System.Text.Encoding.UTF8.GetString(Msg)
Ví dụ tổng hợp 2 hàm chuyển đổi trên:
Private Sub ConvertingDemo()
Dim Msg() As Byte '/// Hỏi thêm: Tại sao không có New !?
Msg = System.Text.Encoding.UTF8.GetBytes("Xin Chao !")
Dim S As String
S = System.Text.Encoding.UTF8.GetString(Msg)
MsgBox("Gia tri cua mang byte Msg la : " & S)
End Sub
a) Tạo một UDPClient gắn vào cổng 10 và Gửi m ột gói tin "Hello" t ới m ột ứng d ụng
UDP khác đang chạy trên máy có địa chỉ là "127.0.0.1" và cổng 1000.
Ung dung A:
Imports System.Net
Imports System.Net.Sockets
Public Class Form1
Const LOCAL_PORT = 10
Const REMOTE_PORT = 1000
'/// Tạo một UDP và gắn (Bind) vào cổng 10
Dim UngDung1 As New UdpClient(LOCAL_PORT)
Private Sub Gửi_Dữ_Liệu()
Biªn so¹n : NguyÔn Minh Quý – Khoa CNTT - §HSPKTHY 11/2006 10
Dim Msg() As Byte
'/// Chuyển chuỗi "Hello there !" thành mảng byte để gửi đi
Msg = System.Text.Encoding.UTF8.GetBytes("Hello there !")
'//// Gửi vào cổng 1000 của máy 127.0.0.1
UngDung1.Send(Msg, Msg.Length, "127.0.0.1", REMOTE_PORT)
End Sub
End Class
b) Tạo một UDPClient gắn vào cổng 1000 và nhận dữ liệu từ ứng dụng khác gửi đến.
Imports System.Net
Imports System.Net.Sockets
Public Class Form1
Const LOCAL_PORT = 1000
Const REMOTE_PORT = 10
Dim UngDung2 As New UdpClient(LOCAL_PORT)
Private Sub Nhận_Dữ_Liệu()
Dim Msg() As Byte
'/// Vì phương thức Receive yêu cầu phải cho biết là nhận từ máy nào (mà
đại
'/// diện cho một máy là một IPEndPoint) nên trước tiên ta cần phải tạo một
'/// IPEndPoint. ở đây ta muốn lấy về từ máy 127.0.0.1 và RemotePort là
100
Dim ep As New IPEndPoint(IPAddress.Parse("127.0.0.1"), 100)
Msg = UngDung2.Receive(ep)
Dim S As String
S = System.Text.Encoding.UTF8.GetString(Msg) '//Chuyển byte -> String
MsgBox(S)
End Sub
End Class
c) Viết chương trình tổng hợp CHAT giữa hai máy dùng giao thức UDP
Mô tả giao diện:
Biªn so¹n : NguyÔn Minh Quý – Khoa CNTT - §HSPKTHY 11/2006 11
Giao diện của ứng dụng A (Ứng dụng 1)
Giao diện của ứng dụng b (Ứng dụng 2)
Code cho mỗi ứng dụng là hoàn toàn giống nhau.
Lưu ý: Nếu 2 ứng dụng đặt trên 2 máy khác nhau thỡ chỳng ta cú thể đặt Remote Port và
Local Port của hai ứng dụng giống nhau (Vỡ khụng bị xung đột).
Listing 1: Chương trình CHAT giữa hai ứng dụng
Biªn so¹n : NguyÔn Minh Quý – Khoa CNTT - §HSPKTHY 11/2006 12
Imports System.Net
Imports System.Net.Sockets
Imports System.Threading
Public Class frmCHAT
Const LOCAL_PORT = 10
Const REMOTE_PORT = 1000
'/// Tạo một UDP và gắn vào cổng 10
Dim UngDung1 As UdpClient
Dim Th As Thread
Dim Thoat As Boolean = False
Public Event Dữ_Liệu_Về (ByVal Data As String, ByVal RemoteHost As String)
------------------------------------------------------------------------------------------------------------------------
Private Sub Thăm_Dò()
'/// Tạo một địa chỉ IP (ở đây dùng GetHostEntry để ta nhập địa chỉ or Hostname)
Dim Ip As IPAddress
Ip = Dns.GetHostEntry(txtRemoteHost.Text).AddressList(0)
Dim Msg() As Byte, S As String
Dim Ep As New IPEndPoint(Ip, Integer.Parse(txtRemotePort.Text))
Do While Thoat = False
Application.DoEvents()
If UngDung1.Available > 0 Then
Msg = UngDung1.Receive(Ep)
S = System.Text.Encoding.UTF8.GetString(Msg)
RaiseEvent Dữ_Liệu_Về (S, Ep.Address.ToString)
End If
Loop
End Sub
------------------------------------------------------------------------------------------------------------------------
Private Sub Gửi_Dữ_Liệu()
Dim Msg() As Byte
'/// Chuyển xâu sáng mảng byte để gửi đi
Msg = System.Text.Encoding.UTF8.GetBytes(txtMsg.Text)
'/// Gửi vào cổng có số hiệu đặt trong txtRemotePort.Text
UngDung1.Send(Msg, Msg.Length, txtRemoteHost.Text, Integer.Parse(txtRemotePort.Text))
End Sub
------------------------------------------------------------------------------------------------------------------------
Private Sub cmdSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)Handles cmdSend.Click
Gửi_Dữ_Liệu ()
lstSent.Items.Insert(0, txtMsg.Text)
txtMsg.Text = ""
End Sub
------------------------------------------------------------------------------------------------------------------------
Biªn so¹n : NguyÔn Minh Quý – Khoa CNTT - §HSPKTHY 11/2006 13
Private Sub frmCHAT_ Dữ_Liệu_Về (ByVal Data As String, ByVal RemoteHost As String) Handles
Me.Dữ_Liệu_Về
Dim Msg As String
Msg = Data & " (Người gửi : " & RemoteHost & ")"
‘lstReceived.Items.Insert(0, Msg)
‘… xử lý
‘…. Xử lý
‘…………..
End Sub
------------------------------------------------------------------------------------------------------------------------
Private Sub frmCHAT_FormClosing(ByVal sender As Object, ByVal e As
System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
Thoat = True '/// Thoát khỏi vòng lặp.
End Sub
------------------------------------------------------------------------------------------------------------------------
Private Sub frmCHAT_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Handles Me.Load
UngDung1 = New UdpClient(Integer.Parse(txtLocalPort.Text))
Th = New Thread(AddressOf Thăm_Dò)
Th.Start()
End Sub
End Class
** Cõu hỏi: Trong sự kiện Dữ_Liệu_Về ta cú thể bỏ bớt tham số RemoteHost đi được
không ? (Hay có thể tăng thêm được không ?)
Biªn so¹n : NguyÔn Minh Quý – Khoa CNTT - §HSPKTHY 11/2006 14
Tổng kết:
Khi muốn gửi dữ liệu qua mạng bằng lớp UDPClient, ta theo cách đơn giản nhất như sau:
1 Tạo một UDPClient và gán (Bind – gắn) Dim udp as New UDPClient(1000)
cho nó một số hiệu cổng.
2 Tạo một địa chỉ IP ứng với địa chỉ của máy Dim IpAdd as IPAddress
mà ta muốn giao tiếp bằng IPEndPoint
hoặc IPAddress hoặc IPHostEntry. (Lưu ý:
Nếu dùng DNS.GetHostEntry thì ta có thể IpAdd = Dns.GetHostEntry("RemoteHost").Address(0)
truyền vào là tên của máy. Sau đó muốn lấy
địa chỉ thì chỉ việc viết, ví dụ:
DNS.GetHostEntry("Tên_Máy").Address(0))
3 Gửi đi dữ liệu đi:
- b1: Chuyển xâu thành mảng byte
- b2 : Gọi phương thức Send, trong đó UDPObj.Send(Msg, IpAdd, RemotePort)
truyền địa chỉ IP của máy ở xa mà ta vừa
tạo ở 2 và thêm vào số hiệu cổng mà máy ở
xa đang dùng để nhận dữ liệu.
Khi nhận: Dùng phương thức Receive để nhận dữ liệu về. Phương thức đòi h ỏi ta ph ải
chỉ ra là lấy về từ máy nào ? (mà đại diện là một IPEndPoint). Khi đó ta c ần tạo m ột đ ối
tượng IPEndPoint với địa chỉ và số hiệu cổng của máy chạy ứng d ụng mà ta mu ốn nh ận
dữ liệu.
Phương thức này trả về cho ta dữ liệu ở dạng mảng byte, do vậy để chuyển sang dạng
xâu ký tự thì cần dùng lớp Encoding để chuyển đổi.
Phương thức Receive làm việc ở chế độ đồng bộ (Tức là sẽ luôn “Blocking” khi ch ưa có
dữ liệu nhận) do vậy thường ta sử dụng cơ chế đa tuyến để gi ải quyết tr ường h ợp này.
(Phần Receive sẽ được đặt trong một tuyến riêng biệt)
Bài tập:
Bài 1: Viết chương trình UDP đặt ở hai máy thực hiện công việc sau:
- Khi một ứng dụng gửi xâu "OPEN#" thì ứng dụng trên máy kia
sẽ mở file nằm trong phần
- Khi một ứng dụng gửi xâu "SHUTDOWN" thì ứng dụng kia sẽ tắt máy tính.
- Khi một ứng dụng gửi xâu "RESTART" thì ứng dụng kia sẽ tắt khởi động lại
máy tính.
Bài 2: Viết chương trình UDP (ứng dụng A) đặt trên một máy. thực hiện các công việc
sau:
- Khi một ứng dụng (B) gửi một xâu chữ Tiếng Anh thì ứng A sẽ gửi trả lại nghĩa tiếng
Việt tương ứng. Nếu từ Tiếng Anh không có trong từ điển (từ điển ở đây chỉ có 3 từ
Computer, RAM, HDD) thì ứng dụng A gửi trả lại xâu "Not found".
…. Viết các ứng dụng khác !
7. Lớp TCP (TCPClient)
7.1 Giới thiệu
Mục đích của lớp UDPClient ở trên là dùng cho lập trình với giao thức UDP, v ới giao th ức
này thì hai bên không cần phải thiết lập kết n ối trước khi gửi do v ậy m ức đ ộ tin c ậy
Biªn so¹n : NguyÔn Minh Quý – Khoa CNTT - §HSPKTHY 11/2006 15
không cao. Để đảm bảo độ tin cậy trong các ứng dụng mạng, người ta còn dùng m ột giao
thức khác, gọi là giao thức có kết nối : TCP (Transport Control Protocol). Trên Internet ch ủ
yếu là dùng loại giao thức này, ví dụ như Telnet, HTTP, SMTP, POP3… Đ ể l ập trình theo
giao thức TCP, MS.NET cung cấp hai lớp có tên là TCPClient và TCPListener.
7.2 Các thành viên của lớp TCPClient
Constructor Method
Name Description
TcpClient ()
Tạo một đối tượng TcpClient. Chưa đặt thông số gỡ.
TcpClient (IPEndPoint) Tạo một TcpClient và gắn cho nú một EndPoint cục
bộ.
(Gán địa chỉ máy cục bộ và số hiệu cổng để sử dụng
trao đổi thông tin về sau)
TcpClient (RemoteHost:
Tạo một đối tượng TcpClient và kết nối đến một
String, RemotePort:
máy có địa chỉ và số hiệu cổng được truyền vào..
Int32)
RemoteHost có thể là địa chỉ IP chuẩn hoặc tên máy.
Public Properties (see also Protected Properties )
Name Description
Available Cho biết số byte đó nhận về từ mạng và cú sẵn để đọc.
Client Trả về Socket ứng với TCPClient hiện hành.
Connected Trạng thái cho biết đó kết nối được đến Server hay
chưa ?
Public Methods (see also Protected Methods )
Name Description
Close Giải phóng đối tượng TcpClient nhưng không đóng
kết nối.
Connect Kết nối đến một máy TCP khác có Tên và số hiệu
(RemoteHost, cổng.
RemotePort)
GetStream Trả về NetworkStream để từ đó giúp ta gửi hay nhận
dữ liệu. (Thường làm tham số khi tạo StreamReader
Biªn so¹n : NguyÔn Minh Quý – Khoa CNTT - §HSPKTHY 11/2006 16
và StreamWriter để gửi và nhận dữ liệu dưới dạng
xâu ký tự) .
Khi đó gắn vào StreamReader và StreamWriter rồi
thỡ ta cú thể gửi và nhận dữ liệu thụng qua cỏc
phương thức Readline, writeline tương ứng của các
lớp này.
Từ cỏc thành viờn của lớp TCPClient ở trờn ta thấy rằng, việc kết nối và thực hiện gửi
nhận rất đơn giản. Theo các trỡnh tự sau:
B1: Tạo một đối tượng TCPClient
B2: Kết nối đến máy chủ (Server) dùng phương thức Connect
B3: Tạo 2 đối tượng StreamReader (Receive)và StreamWriter (Send) và "nối" với
GetStream của TCPClient
B4: - Dùng đối tượng StreamWriter.Writeline/write vừa tạo ở trên để gửi dữ liệu đi.
- Dùng đối tượng StreamReader.Readline/Read vừa tạo ở trên để đọc dữ liệu về.
B5: Đóng kết nối.
*** Nếu muốn gửi/nhận dữ liệu ở mức byte (nhị phõn) thỡ dựng NetworkStream. (truyền
GetStream cho NetworkStream)
7.3 Ví dụ
a) Tạo một TCP Client và kết nối đến server (FTP Server-listen on 21 port), sau đó gửi 1
xâu.
Imports System.Net.Sockets
Imports System.Net
Imports System.IO
Public Class Form1
'/// Tạo địa chỉ ứng với 127.0.0.1 (Có thể sử dụng nhiều cách đó được đề cập)
Dim DiaChi As Long = 1 * 256 ^ 3 + 127 * 256 ^ 0 '//= 127.0.0.1
'// Tạo một IPEndPoint từ địa chỉ IP và cổng (Vỡ TCPClient cần một IPEndPoint)
Dim LocalEP As New IPEndPoint(DiaChi, 100) '// cho cục bộ (client)
'/// Tạo một đối tượng TCP ứng với địa chỉ và cổng ở trên
Dim tcp As New TcpClient(LocalEP)
'/// Hai luồng nhập và xuất dùng để đọc/ghi vào kết nối TCP
Dim Ghi As StreamWriter
Dim Doc As StreamReader
Private Sub Form1_Load(…)
tcp.Connect("localhost", 21) ‘//Kết nối đến máy chủ FTP
'MsgBox(tcp.Connected)
'/// Nối
Doc = New StreamReader(tcp.GetStream())
Ghi = New StreamWriter(tcp.GetStream())
Biªn so¹n : NguyÔn Minh Quý – Khoa CNTT - §HSPKTHY 11/2006 17
'/// Gửi thử một xõu (tên đăng nhập) cho server (FTP Server)
Ghi.Writeline("User quynm")
Ghi.Flush()
'/// Đọc dữ liệu do Server gửi về
Dim S As String
S = Doc.ReadLine()
MsgBox("Dữ liệu gửi từ server : " & S)
End Sub
Private Sub Gui_Du_Lieu(ByVal Data As String)
Ghi.WriteLine(Data)
Ghi.Flush()
End Sub
End Class
b) Ở vớ dụ trờn ta thấy rằng việc gửi thỡ cú thể thực hiện nhiều lần với việc gọi nhi ều
lần phương thức Gửi_Dữ_Liệu. Tuy nhiên, đối với việc nhận dữ liệu thỡ ta chỉ thực hiện
một lần. Trong trường hợp nếu ta muốn nhận dữ liệu bất cứ khi nào có d ữ li ệu về th ỡ
cần áp dụng kỹ thuật "Thăm dũ" và "kớch hoạt sự kiện" như trong phần UDPClient.
í tưởng thực hiện như sau:
B1 : Tạo một TCPClient
B2 : Kết nối
B3 : Tạo một luồng mới, luồng này "chuyờn theo dừi" xem cú dữ li ệu m ới về hay kh ụng
(chỉ việc kiểm tra bộ đệm (đối tượng StreamReader.EndOfStream = True/False). N ếu b ộ
đệm không rỗng (có dữ liệu mới) thỡ giỏ trị EndOfStream sẽ bằng False. Khi có d ữ li ệu
trong bộ đệm thỡ ta kớch hoạt (Raise) sự kiện Cú_Dữ_Liệu lờn. Trong sự ki ện này ta sẽ
viết cỏc lệnh xử lý.
Listing 2 : Viết chương trỡnh Telnet
Imports System.Net.Sockets
Imports System.Net
Imports System.IO
Imports System.Threading
Public Class frmTelnet
'/// Tạo một đối tượng TCPClient
Dim tcp As New TcpClient()
'/// Hai luồng nhập và xuất dùng để ghi vào kết nối TCP
Dim Ghi As StreamWriter
Dim Doc As StreamReader
'/// Tạo một thread chuyên thăm dũ dữ liệu
Dim Th As Thread
Biªn so¹n : NguyÔn Minh Quý – Khoa CNTT - §HSPKTHY 11/2006 18
'/// Cờ báo hiệu khi thoát. Để tránh việc lặp vô hạn
Dim Thoat As Boolean = False
Public Event Dữ_Liệu_Về(ByVal Data As String)
Sub Thăm_Dũ()
Dim S As String
Do While Thoat = False
Application.DoEvents()
If Doc.EndOfStream = False Then
S = Doc.ReadLine
RaiseEvent Dữ_Liệu_Về(S)
End If
Loop
End Sub
Private Sub frmTelnet_Dữ_Liệu_Về(ByVal Data As String) Handles Me.Dữ_Liệu_Về
lstreceived.Items.Insert(0, Data)
End Sub
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim RPort As Long = Integer.Parse(txtRemotePort.Text)
Dim IpEnd As New IPEndPoint(IPAddress.Parse(txtRemoteHost.Text), RPort)
'/// Kết nối tới mỏy chủ
tcp.Connect(IpEnd)
Doc = New StreamReader(tcp.GetStream())
Ghi = New StreamWriter(tcp.GetStream())
Th = New Thread(AddressOf Thăm_Dũ)
Th.Start()
End Sub
Private Sub cmdSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSend.Click
Gui_Du_Lieu(txtMsg.Text)
End Sub
Private Sub frmTelnet_FormClosing(ByVal sender As Object, ByVal e As
System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
Thoat = True
End Sub
Private Sub Gui_Du_Lieu(ByVal Data As String)
Ghi.WriteLine(Data)
Ghi.Flush()
lstSent.Items.Insert(0, txtMsg.Text)
End Sub
Biªn so¹n : NguyÔn Minh Quý – Khoa CNTT - §HSPKTHY 11/2006 19
End Class
Giao diện:
Ghi chỳ: Nếu muốn đọc hay ghi dữ liệu ở dạng chuỗi byte thỡ khai bỏo Doc, Ghi As
NetworkStream.
Bài tập: Viết ứng dụng chơi cờ Caro / Cờ tướng (Hay bất kỳ cờ gỡ khỏc !!!) qua mạng.
(Sử dụng giao thức UDP). Gợi ý: mỗi khi người dùng đi thỡ sẽ gửi v ị trí c ủa ô v ừa đi cho
ứng dụng kia (đối phương).
8. Lớp TCPListener
8.1 Giới thiệu
TCPListerner là một lớp cho phép người lập trỡnh cú th ể xây d ựng các ứng d ụng Server
(Ví dụ như SMTP Server, FTP Server, DNS Server, POP3 Server hay server t ự đ ịnh nghĩa
….). Ứng dụng server khác với ứng dụng Client ở chỗ nó luôn luôn th ực hi ện l ắng nghe
và chấp nhận các kết nối đến từ Client.
8.2 Các thành viên của lớp
Constructor method
Name Description
TcpListener (Port: Int32)
Tạo một TcpListener và lắng nghe tại cổng chỉ
Biªn so¹n : NguyÔn Minh Quý – Khoa CNTT - §HSPKTHY 11/2006 20