Tải bản đầy đủ (.pdf) (41 trang)

Tìm hiểu lập trình Socket TCP và ứng dụng truyền file qua mạng

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 (543.72 KB, 41 trang )

Trang 1
Trang 2
LỜI MỞ ĐẦU
Ngày nay vấn đề toàn cầu hóa thông tin và tốc độ phát triển của khoa học công
nghệ diễn ra một cách nhanh chóng, một kỷ nguyên mới được mở ra; kỷ nguyên của
xã hội hóa thông tin. Công nghệ thông tin và truyền thông phát triển đã đưa thế giới
chuyển sang thời đại mới, thời đại của công nghệ thông tin. Việc nắm bắt và ứng dụng
Công nghệ thông tin trong các lĩnh vực khoa học, kinh tế, xã hội đã đem lại cho các
doanh nghiệp và các tổ chức những thành tựu và lợi ích to lớn.
Máy tính đã trở thành công cụ đắc lực và không thể thiếu của con người. Các tổ
chức, công ty hay các cơ quan cần phải xây dựng hệ thống mạng máy tính cho riêng
mình để trao đổi dữ liệu giữa các bộ phận. Dữ liệu được truyền đi trên mạng phải đảm
bảo: dữ liệu được chuyển tới đích nhanh chóng và đúng đắn. Hầu hết dữ liệu được
truyền qua mạng là truyền dưới dạng file.
Nhằm tìm hiểu thấu đáo một trong các phương pháp truyền file qua mạng, em
chọn đề tài “Tìm hiểu lập trình Socket TCP và ứng dụng truyền file qua mạng”.

Trang 3
CHƯƠNG 1: CƠ SỞ LÝ THUYẾT THỰC HIỆN ĐỀ TÀI
1.1. Bộ giao thức TCP/IP.
Tầng Transport
Trong các ngành tin học và viễn thông, tầng giao vận là tầng thứ tư trong bảy
tầng của mô hình OSI. Tầng này chịu trách nhiệm đáp ứng các đòi hỏi về dịch vụ của
tầng phiên và đưa ra các yêu cầu dịch vụ đối với tầng mạng.
Tầng giao vận cung cấp dịch vụ xuyên dụng chuyển dữ liệu giữa các máy chủ
(hosts). Tầng này chịu trách nhiệm sửa lỗi (error recovery), điều khiển lưu lượng dữ
liệu, đảm bảo dữ liệu được chuyển tải một cách trọn vẹn. Trong Bộ giao thức liên
mạng - TCP/IP, chức năng này thường được thực hiện bởi giao thức định hướng kết
nối TCP.
Giao vận kiểu datagram, UDP - Giao thức Datagram Người dùng, không cung
cấp dịch vụ sửa lỗi hay điều khiển lưu lượng dữ liệu mà dành nhiệm vụ này cho phần


mềm ứng dụng. Mục đích của tầng giao vận là cung cấp dịch vụ xuyên dụng chuyển
dữ liệu giữa các người dùng đầu cuối, nhờ đó các tầng trên không phải quan tâm đến
việc cung cấp dịch vụ truyền dữ liệu đáng tin cậy và hiệu quả.
Tậng giao vận thường biến dịch vụ đơn giản, có độ tin cậy thấp của tầng mạng
thành một dịch vụ mạnh hơn. Có một danh sách dài liệt kê những dịch vụ có thể được
cung cấp bởi tầng này. Không có một dịch vụ nào trong đó là bắt buộc cả, bởi vì
không phải chương trình ứng dụng nào cũng yêu cầu tất cả những dịch vụ hiện có. Một
số dịch vụ làm lãng phí chi phí phụ, hoặc trong vài trường hợp còn gây phản tác dụng.
Định hướng kết nối (Connection-Oriented)
Dịch vụ này thường dễ dùng hơn là các mô hình phi kết nối (connection-less
model), vì thế cho nên ở những nơi mà tầng mạng chỉ cung cấp dịch vụ phi kết nối,
thường có dịch vụ hướng kết nối được xây dựng chồng lên trên nó, tại tầng giao vận.
Phân phát theo trật tự đã gửi (Same Order Delivery)
Tầng mạng thường không đảm bảo các gói dữ liệu đến theo trật tự mà nó được
gửi, song đặc tính này lại là một đặc tính có ưu điểm, nhưng thông thường đây lại là
Trang 4
một đặc tính được trọng dụng, vì vậy cho nên tầng giao vận phải đảm bảo việc này.
Cách đơn giản nhất là gắn cho mỗi gói dữ liệu một con số, để cho thiết bị nhận sắp xếp
lại trật tự của các gói dữ liệu.
Dữ liệu đáng tin cậy (Reliable Data)
Mạng truyền thông nền tảng có thể có độ nhiễu cao, và dữ liệu nhận được không
phải bao giờ cũng giống như dữ liệu đã được gửi. Tầng giao vận có thể sửa lỗi này:
thường là bằng cách cung cấp một giá trị tổng kiểm của dữ liệu, giá trị đó phát hiện
một số dạng sai sót nhỏ. Đương nhiên, truyền thông tín hiệu hoàn toàn không có lỗi là
một việc không khả thi, song giảm đáng kể số lỗi không được phát hiện là một việc có
thể thực hiện được. Tầng giao vận còn có thể truyền lại những gói dữ liệu bị thất lạc
trên đường truyền.
Điều khiển lưu lượng (Flow Control)
Lượng bộ nhớ trong máy tính chỉ có hạn. Nếu không điều khiển lưu lượng dữ
liệu, thì một máy tính lớn có thể làm ngập một máy khác với lượng thông tin quá lớn

làm máy tính đó không kịp xử lý dữ liệu. Hiện tại, vấn đề này không phải là một vấn
đề lớn, vì giá của bộ nhớ rẻ, trong khi giá của băng thông (bandwidth) lại đắt, song
trước đây, vấn đề này đã là một vấn đề quan trọng. Việc điều khiển lưu lượng cho
phép thiết bị nhận dữ liệu nói "Khoan nào!" trước khi nó bị tràn. Đôi khi chức năng
này đã được mạng nền tảng cung cấp, song tầng giao vận có thể gắn thêm chức năng
này nếu chưa có.
Định hướng byte (Byte Orientation)
Thay vì giải quyết các vấn đề theo từng gói dữ liệu, tầng giao vận có thể bổ sung
khả năng nhìn dữ liệu truyền thông như là một dòng các byte (ký tự). Cách này dễ giải
quyết hơn là khi các gói dữ liệu có kích thước ngẫu nhiên, song nó ít khi khớp với mô
hình truyền thông mà thông thường sẽ là một dãy các thông điệp có kích thước do
người dùng xác định.
Cổng (Port)
Về căn bản, cổng là phương pháp đánh địa chỉ các thực thể khác nhau tại cùng
một địa điểm. Ví dụ, dòng đầu tiên trên một địa chỉ gửi thư có thể hiểu là một dạng
Trang 5
cổng, nó phân biệt giữa các cư dân khác nhau trong cùng một ngôi nhà. Các chương
trình ứng dụng lắng nghe thông tin trên các cổng riêng của nó, và chính vì vậy mà
chúng ta có thể dùng nhiều chương trình ứng dụng mạng trong cùng một lúc.
Trên Internet có rất nhiều dịch vụ của tầng giao vận, song hai dịch vụ thường
dùng nhất là TCP và UDP. TCP phức tạp hơn, nó cung cấp kết nối và dòng định
hướng byte, dòng này hầu như không có lỗi, với các dịch vụ điều khiển lưu lượng dữ
liệu, nhiều cổng, và phân phát dữ liệu đúng trật tự. UDP là một dịch vụ datagram đơn
giản, nó cung cấp khả năng giảm lỗi hạn chế (limited error reduction) và có nhiều
cổng. TCP là chữ viết tắt của thuật ngữ tiếng Anh "Transmission Control Protocol" -
tạm dịch là "Giao thức điều khiển truyền vận". UDP là chữ viết tắt của thuật ngữ tiếng
Anh "User Datagram Protocol" - tạm dịch là "Giao thức datagram người dùng". Các
lựa chọn khác bao gồm Giao thức kiểm soát tắc nghẽn gói dữ liệu (Datagram
Congestion Control Protocol - DCCP) và Giao thức truyền vận điều khiển dòng
(Stream Control Transmission Protocol - SCTP).

Một vài dịch vụ, chẳng hạn như định hướng kết nối (connection orientation) có
thể được cài đặt tại tầng giao vận hay tầng mạng. Tư tưởng là tầng mạng cài đặt một
tập các lựa chọn nào dễ nhất: đối với một số mạng truyền thông, cài đặt truyền thông
phi kết nối là việc dễ dàng nhất, trong khi đối với các mạng khác, việc cài đặt truyền
thông hướng kết nối lại dễ hơn cả. Tầng giao vận sử dụng nhóm các lựa chọn đơn giản
nhất này để cài đặt bất cứ tổ hợp của các lựa chọn nào mà trong thực tế được mong
muốn.
Giao thức trao đổi dữ liệu "có liên kết" (connection - oriented) TCP được sử
dụng ở tầng vận chuyển để đảm bảo tính chính xác và tin cậy việc trao đổi dữ liệu dựa
trên kiến trúc kết nối "không liên kết" ở tầng liên mạng IP.
Trang 6
Hình 1.1 Mô hình tham chiếu và giao thức TCP/IP
UDP (User Datagram Protocol) là một trong những giao thức cốt lõi của giao
thức TCP/IP. Dùng UDP, chương trình trên mạng máy tính có thể gởi những dữ liệu
ngắn được gọi là datagram tới máy khác. UDP không cung cấp sự tin cậy và thứ tự
truyền nhận mà TCP làm. Các gói dữ liệu có thể đến không đúng thứ tự hoặc bị mất
mà không có thông báo. Tuy nhiên UDP nhanh và hiệu quả hơn đối với các mục tiêu
như kích thước nhỏ và yêu cầu khắt khe về thời gian. Do bản chất không trạng thái của
nó nên nó hữu dụng đối với việc trả lời các truy vấn nhỏ với số lượng lớn người yêu
cầu.
TCP (Transmission Control Protocol - "Giao thức điều khiển truyền vận") là
một trong các giao thức cốt lõi của bộ giao thức TCP/IP. Sử dụng TCP, các ứng dụng
trên các máy chủ được nối mạng có thể tạo các "kết nối" với nhau, mà qua đó chúng
có thể trao đổi dữ liệu hoặc các gói tin. Giao thức này đảm bảo chuyển giao dữ liệu tới
nơi nhận một cách đáng tin cậy và đúng thứ tự. TCP còn phân biệt giữa dữ liệu của
Trang 7
nhiều ứng dụng (chẳng hạn, dịch vụ Web và dịch vụ thư điện tử) đồng thời chạy trên
cùng một máy chủ.
Các header của TCP và UDP khác nhau ở kích thước (20 và 8 byte) nguyên
nhân chủ yếu là do TCP phải hộ trợ nhiều chức năng hữu ích hơn(như khả năng khôi

phục lỗi). UDP dùng ít byte hơn cho phần header và yêu cầu xử lý từ host ít hơn.
Đối với giao thức TCP dùng cho mạng WAN; không cho phép mất gói tin; đảm
bảo việc truyền dữ liệu; tốc độ truyền thấp hơn UDP.
Đối với giap thức UDP dùng cho mạng LAN; cho phép mất dữ liệu; không đảm
bảo; tốc độ truyền cao, VolP truyền tốt qua UDP.
1.2. Giao thức IP.
Giao thức Internet phiên bản 4 (viết tắt IPv4, từ tiếng Anh Internet Protocol
version 4) là phiên bản thứ tư trong quá trình phát triển của các giao thức Internet (IP).
Đây là phiên bản đầu tiên của IP được sử dụng rộng rãi. IPv4 cùng với IPv6 (giao thức
Internet phiên bản 6) là nòng cốt của giao tiếp internet. Hiện tại, IPv4 vẫn là giao thức
được triển khai rộng rãi nhất trong bộ giao thức của lớp internet.
Giao thức này được công bố bởi IETF trong phiên bản RFC 791 (tháng 9 năm
1981), thay thế cho phiên bản RFC 760 (công bố vào tháng giêng năm 1980). Giao
thức này cũng được chuẩn hóa bởi bộ quốc phòng Mỹ trong phiên bản MIL-STD-
1777.
IPv4 là giao thức hướng dữ liệu, được sử dụng cho hệ thống chuyển mạch gói
(tương tự như chuẩn mạng Ethernet). Đây là giao thức truyền dữ liêu hoạt động dựa
trên nguyên tắc tốt nhất có thể, trong đó, nó không quan tâm đến thứ tự truyền gói tin
cũng như không đảm bảo gói tin sẽ đến đích hay việc gây ra tình trạng lặp gói tin ở
đích đến. Việc xử lý vấn đề này dành cho lớp trên của chồng giao thức TCP/IP. Tuy
nhiên, IPv4 có cơ chế đảm bảo tính toàn vẹn dữ liệu thông qua sử dụng những gói
kiểm tra (checksum).
Địa chỉ IP đang được sử dụng hiện tại (IPv4) có 32 bit chia thành 4 Octet ( mỗi
Octet có 8 bit, tương đương 1 byte ) cách đếm đều từ trái qua phải bít 1 cho đến bít 32,
các Octet tách biệt nhau bằng dấu chấm (.). VD 1 địa chỉ IP như sau: 196.84.156.67.
Trang 8
Địa chỉ IP được chia thành 4 số giới hạn từ 0 - 255 (vì 255 tương đương 11111111 (ở
hệ nhị phân) là số lớn nhất có 8 bit).
Địa chỉ IP chia ra 5 lớp A,B,C, D, E. Hiện tại đã dùng hết lớp A,B và gần hết
lớp C, còn lớp D và E Tổ chức internet đang để dành cho mục đích khác không phân,

nên chúng ta chỉ nghiên cứu 3 lớp đầu. Bit nhận dạng là những bit đầu tiên - của lớp A
là 0, của lớp B là 10, của lớp C là 110. Lớp D có 4 bit đầu tiên để nhận dạng là 1110,
còn lớp E có 4 bít đầu tiên để nhận dạng là 1111. Do đó địa chỉ ví dụ ở trên bắt đầu
bằng 11000100 nên thuộc lớp C.
Một địa chỉ IP được phân biệt bởi hai phần, phần đầu gọi là Network ID (địa
chỉ mạng) và phần sau là Host ID. Ví dụ đối với lớp A (có địa chỉ từ 0.0.0.0 đến
127.0.0.0 ), bit thứ nhất là bit nhận dạng lớp A = 0, 7 bit còn lại trong Octet thứ nhất
dành cho địa chỉ mạng, 3 Octet còn lại có 24 bit dành cho địa chỉ của máy chủ. Do
vậy, trên lớp A, có thể phân cho 126 mạng khác nhau, và mỗi mạng có thể có tối đa
16777214 máy host.
Sự khác nhau đáng kể nhất giữa IPv4 và IPv6 là chiều dài của địa chỉ nguồn và
địa chỉ của chúng. Việc chuyển sang sử dụng IPv6 là do ngày càng thiếu về số địa chỉ
IP. Giao thức IPv6 này có một không gian địa chỉ lớn hơn so với giao thức IPv4.
iao thức IPv4 sử dụng một địa chỉ nguồn và địa chỉ đích là 32bit. Các địa chỉ này được
biểu diễn thành bốn phần. Một địa chỉ IPv4 điển hình có dạng như 192.168.0.1.
Tương phản với IPv4, địa chỉ IPv6 có chiều dài là 128bit. Điều đó cho phép có
thể biểu diễn đến 3.4x1038 (340.000.000.000.000.000.000.000.000.000.000.000.0 00)
địa chỉ. Có một vài sự khác nhau trong cách biểu diễn địa chỉ của IPv6. Một địa chỉ
IPv6 thường được viết thành 8 nhóm, mỗi nhóm gồm có 4 số hex và mỗi nhóm được
tách biệt với nhau bằng dấu “:”. Ví dụ như sau thể hiện điều này
2001:0f68:0000:0000:0000:0000:1986:69af.
Bạn đang xem xét địa chỉ mẫu ở trên và nghĩ rằng việc đánh một địa chỉ IPv6
phải rất mất thời gian và công sức? Nhưng không phải như vậy, địa chỉ IPv6 chỉ có thể
được viết vắn tắt bằng việc giảm thiểu các số 0. Có hai nguyên tắc phải tuân theo ở
đây khi biểu diễn một địa chỉ IP. Đầu tiên, một dãy bốn số 0 liên tục có thể được thay
Trang 9
thế bằng hai dấu “::”. Bằng cách đó địa chỉ IPv6 ở trên có thể được viết tắt như sau:
2001:0f68::0000:0000:0000:1986:69af.
Trong ví dụ ở trên, chúng ta chỉ có thể ước lượng một khối các chữ số 0 bởi vì
nguyên tắc này phát biểu rằng chỉ có một cặp “::” trong một địa chỉ. Rõ ràng, địa chỉ

mà đang ví dụ ở trên vẫn còn rất nhiều chữ số cần phải đánh. Tuy nhiên, nguyên tắc
thứ hai sẽ cho phép bạn thực hiện địa chỉ này ngắn hơn. Nguyên tắc thứ hai nói rằng,
các số 0 trong một nhóm có thể được bỏ qua. Nếu một khối 4 số bắt đầu của nó là số 0
thì số 0 này có thể được lược bỏ bớt để lại là 3 số 0 trong khối. Nếu khối ba số đó cũng
lại bắt đầu với một số 0 đứng đầu thì ta có thể tiếp tục loại bỏ. Và cứ như vậy đến khi
gặp số khác 0 trong nhóm thì dừng. Trường hợp nếu 4 số trong nhóm đều là 0 thì số
được giữ lại cuối cùng là một số 0. Nếu cứ nói mãi mà không biểu diễn trong ví dụ cụ
thể để các bạn dễ theo dõi thì đó là một thiếu sót. Dưới đây là những gì mà chúng ta có
thể áp dụng cả hai nguyên tắc đó cho địa chỉ ví dụ:
2001:0f68:0000:0000:0000:0000:1986:69af
2001:f68:000:000:000:000:1986:69af
2001:f68:00:00:00:00:1986:69af
2001:f68:0:0:0:0:1986:69af
2001:f68::1986:69af
1.3. Lập trình mạng trong .NET.
1.3.1. Nền tảng của .NET.
Microsoft .Net không phải là một ngôn ngữ lập trình, đó là một không gian làm
việc tổng hợp bởi bốn bộ ngôn ngữ lập trình: C#, VB.NET, Managed C++, and J#
.NET. ở đó có sự chồng gối lên nhau của các ngôn ngữ, và được định nghĩa trong FCL
(framework class library).
Microsoft .Net bao gồm 2 phần chính: Framework và Intergrated Development
Enviroment (IDE). Framework cung cấp những gì cần thiết và căn bản, là khuôn dạng
hay môi trường hỗ trợ các hạ tầng cơ sở theo một quy ước nhất định để công việc được
thuận tiện. IDE cung cấp một môi trường giúp chúng ta triển khai dễ dàng và được
nhanh chóng các ứng dụng dựa trên nền tảng .Net.
Trang 10
Thành phần Framework là quan trọng nhất .NET là cốt lõi và tinh hoa của môi
trường, còn IDE chỉ là công cụ để phát triển dựa trên nền tảng đó thôi. Trong .NET
toàn bộ các ngôn ngữ C#, Visual C++ hay Visual Basic.NET đều dùng cùng một IDE.
Microsoft .NET là nền tảng cho việc xây dựng và thực thi các ứng dụng phân tán

thế hệ kế tiếp. Bao gồm các ứng dụng từ client đến server và các dịch vụ khác. Một số
tính năng của Microsoft .NET cho phép những nhà phát triển sử dụng như sau:
- Một mô hình lập trình cho phép nhà phát triển xây dựng các ứng dụng dịch vụ
web và ứng dụng client với Extensible Markup Language (XML).
- Tập hợp dịch vụ XML Web, như Microsoft .NET My Services cho phép nhà
phát triển đơn giản và tích hợp người dùng kinh nghiệm.
- Cung cấp các server phục vụ bao gồm: Windows 2000, SQL Server, và
BizTalk Server, tất cả điều tích hợp, hoạt động, và quản lý các dịch vụ XML Web và
các ứng dụng.
- Các phần mềm client như Windows XP và Windows CE giúp người phát triển
phân phối sâu và thuyết phục người dùng kinh nghiệm thông qua các dòng thiết bị.
- Nhiều công cụ hỗ trợ như Visual Studio .NET, để phát triển các dịch vụ Web
XML,ứng dụng trên nền Windows hay nền web một cách dể dàng và hiệu quả.
C# là một ngôn ngữ rất đơn giản, với khoảng 80 từ khoá và hơn mười kiểu dữ
liệu dựng sẵn, nhưng C# có tính diễn đạt cao. C# hỗ trợ lập trình có cấu trúc, hướng
đối tượng, hướng thành phần (component oriented).
Trọng tâm của ngôn ngữ hướng đối tượng là lớp. Lớp định nghĩa kiểu dữ liệu
mới, cho phép mở rộng ngôn ngữ theo hướng cần giải quyết. C# có những từ khoá
dành cho việc khai báo lớp, phương thức, thuộc tính (property) mới. C# hỗ trợ
đầy đủ khái niệm trụ cột trong lập trình hướng đối tượng: đóng gói, thừa kế, đa hình.
Định nghĩa lớp trong C# không đòi hỏi tách rời tập tin tiêu đề với tập tin cài đặt
như C++. Hơn thế, C# hỗ trợ kiểu sưu liệu mới, cho phép sưu liệu trực tiếp trong tập
tin mã nguồn. Đến khi biên dịch sẽ tạo tập tin sưu liệu theo định dạng XML.
Trang 11
C# hỗ trợ khái niệm giao diện, interfaces (tương tự Java). Một lớp chỉ có
thể kế thừa duy nhất một lớp cha nhưng có thế cài đặt nhiều giao diện.
C# có kiểu cấu trúc, struct (không giống C++). Cấu trúc là kiểu hạng nhẹ và bị
giới hạn.Cấu trúc không thể thừa kế lớp hay được kế thừa nhưng có thể cài đặt giao
diện.
C# cung cấp những đặc trưng lập trình hướng thành phần như property, sự kiện

và dẫn hướng khai báo (được gọi là attribute). Lập trình hướng component được hỗ trợ
bởi CLR thông qua siêu dữ liệu (metadata). Siêu dữ liệu mô tả các lớp bao gồm các
phương thức và thuộc tính, các thông tin bảo mật.
Assembly là một tập hợp các tập tin mà theo cách nhìn của lập trình viên là các
thư viện liên kết động (DLL) hay tập tin thực thi (EXE). Trong .NET một assembly
là một đơn vị của việc tái sử dụng, xác định phiên bản, bảo mật, và phân phối. CLR
cung cấp một số các lớp để thao tác với assembly.
C# cũng cho truy cập trực tiếp bộ nhớ dùng con trỏ kiểu C++, nhưng vùng mã đó
được xem như không an toàn. CLR sẽ không thực thi việc thu dọn rác tự động các đối
tượng được tham chiếu bởi con trỏ cho đến khi lập trình viên tự giải phóng.
1.3.2. Sử dụng các lớp hỗ trợ được xây dựng từ lớp Socket.
1.3.2.1. Lớp TCPClient.
Dùng 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 dộ tin cậy không cao. Để đảm bảo độ tin cậy trong các ứng dụng mạng người
ta còn sử dụng một giao thức khác gọi là giao thức có kết nối: TCP (transport control
protocol). Để lập trình theo giao thức TCP, MS.NET cung cấp hai lớp có tên là
TCPClient và TCPListener.
Các thành phần của lớp TcpClient.
Phương thức khởi tạo:
Constructor method (phương pháp xây dựng)
Name Description (mô tả)
Trang 12
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:

String Int32)
Tạo một đối tượng TcpClient và kết nối đến
một máy có địa chỉ và số hiệu cổng được
truyền vào. RemoteHost có thể là địa chỉ IP
chuẩn hoặc tên máy.
Một số thuộc tính:
Name Description (mô tả)
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?
Một số phương thức:
Name Description (mô tả)
Close
Giải phóng đối tượng TcpClient nhưng không đóng
kết nối.
Connect (RemoteHost,
Port)
Kết nối đến một máy TCP khác có tên và số hiệu
cổng.
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
và StreamWriter).
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 Readln, writeline tương ứng của các
lớp này.
Trang 13
1.3.2.2. Lớp TCPListener.
TCPListener 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.
Các thành phần của lớp TcpListent:
Phương thức khởi tạo:
Constructor method (phương pháp xây dựng)
Name Description (mô tả)
TcpListener (Port: Int32)
Tạo một TcpListener và lắng nghe tại cổng chỉ
định.
TcpListener (IPAddress,
Int32)
Tạo một TcpListener và lắng nghe các kết nối đến
tại địa chỉ IP và cổng chỉ định.
TcpListener (IPEndPoint)
Tạo một TcpListener với giá trị EndPoint truyền
vào.
Các phương thức khác:
Name Description (mô tả)
AcceptTcpClient
Chấp nhận một yêu cầu kết nối đang chờ. (ứng dụng sẽ dừng
tại câu lệnh này cho đến khi nào có một kết nối đến).
AcceptSocket Chấp nhận một yêu cầu kết nối đang chờ.
Pending Cho biết liệu có kết nối nào đang chờ đợi không? ( True = có).
Start Bắt đầu lắng nghe các yêu cầu kết nối.
Stop Dừng việc nghe.
1.3.3. Socket không đồng bộ.
Sử dụng Socket không đồng bộ.
Để lập trình không đồng bộ với Socket chúng ta sử dụng các phương thức cho
việc sử dụng bất đồng bộ.
Trang 14
Các phương thức cho việc lập trình bất đồng được chia làm 2 bắt đầu bằng Begin

và End:
Phương thức bắt đầu bằng Begin, bắt đầu một chức năng và được đăng ký với
phương thức AsyncCallback.
Bắt đầu bằng End chỉ chức năng hoàn thành khi AsyncCallback đươc gọi
Requests Started By … Description of Request
Requests Ended BY …
BeginAccept ()
To accept an incoming
connection.
EndAccept ()
BeginConnect () To connect to a remote host. EndConnect ()
BeginReceive () To retrieve data from a socket. EndReceive ()
BeginReceiveFrom ()
To retrieve data from a specific
remote host.
EndReciveFrom()
BeginSend () To send data from a socket. EndSend ()
BeginSendTo ()
To send data to a specific remote
host.
EndSendTo ()
Để chấp nhận kết nối bất đồng bộ ta sử dụng phương thức BeginAccept() và
EndAccept() như sau:
- Phương thức BeginAccept() và EndAccept().
IAsyncResult BeginAccept(AsyncCallback callback, object state)
Socket EndAccept(IAsyncResult iar);
Để thiết lập phương thức kết nối theo cách bất đồng bộ ta sử dụng phương thức
BeginConnect() và EndConnect() như sau:
- Phương thức BeginConnect() và EndConnect().
Socket newsock = new Socket (AddressFamily.InterNetwork,

SocketType.Stream, ProtocolType.Tcp) ;
IPEndPoint iep =new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050);
newsock.BeginConnect (iep, new AsyncCallback (Connected), newsock);
- Trong đó phương thức Connected thường được viết như sau:
Trang 15
public static void Connected(IAsyncResult iar)
{
Socket sock = (Socket)iar.AsyncState;
try
{
sock.EndConnect(iar);
}
catch (SocketException)
{
Console.WriteLine("Unable to connect to host");
}
}
Để gửi dữ liệu bất đồng bộ chúng ta làm như sau:
- Phương thức BeginSend() và EndSend().
BeginSend()
IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags
sockflag, AsyncCallback callback, object state)
EndSend()
int EndSend(IAsyncResult iar)
- Trong đó phương thức SendData thường được viết như sau:
private static void SendData(IAsyncResult iar)
{
Socket server = (Socket)iar.AsyncState;
int sent = server.EndSend(iar);
}

Tương tự như giao thức hướng kết nối nếu ta sử dụng gửi dữ liệu theo giao thức
không hướng kết nối chúng ta cũng thực hiện tương tự như sau:
- Phương thức BeginSendTo() và EndSendTo().
Trang 16
IAsyncResult BeginSendTo(byte[] buffer,int offset,int size,SocketFlags
sockflag, EndPoint ep, AsyncCallback callback, object state)
Để nhận dữ liệu bất đồng bộ ta thực hiện như sau:
Nhận dữ liệu với giao thức hướng kết nối:
- Phương thức BeginRecieve và EndRecive()
sock.BeginReceive(data, 0, data.Length, SocketFlags.None, new
AsyncCallback(ReceivedData), sock);
Với ReceivedData được định nghĩa như sau:
void ReceivedData(IAsyncResult iar)
{
Socket remote = (Socket)iar.AsyncState;
Int recv = remote.EndReceive(iar);
string receivedData = Encoding.ASCII.GetString(data, 0, recv);
Console.WriteLine(receivedData);
}
Nhận dữ liệu bất đồng bộ với giao thức không hướng kết nối.
- Phương thức BeginReceiveFrom() và EndReceiveFrom()
sock.BeginReceive(data,0,data.Length,SocketFlags.None,refiep,new
AsyncCallback (ReceiveData) , sock);
void ReceiveData(IasyncResult iar)
{
Socket remote = (Socket)iar.AsyncState;
int recv = remote.EndReceiveFrom(iar);
string stringData = Encoding.ASCII.GetString(data, 0, recv);
Console.WriteLine(stringData);
Trang 17

}
1.3.4. Sử dụng Thread trong các ứng dụng mạng.
Một số khái niệm.
Đa nhiệm (multitasking): là khả năng hệ điều hành làm nhiều công việc tại một
thời điểm.
Tiến trình (Process): khi chạy một ứng dụng hệ điều hành sẽ cấp phát riêng cho
ứng dụng đó bộ nhớ và các tài nguyên khác. Bộ nhớ và tài nguyên vật lý riêng biệt này
được gọi là một tiến trình. Các tài nguyên và bộ nhớ của một tiến trình thì chỉ tiến
trình đó được phép truy cập.
Tuyến (Thread ): trong hệ thống một tiến trình có thể có một hoặc nhiều chuỗi
thực hiện tách biệt khác nhau và có thể chạy đồng thời. mỗi chuỗi thực hiện này được
gọi là 1 tuyến (Thread). Trong 1 ứng dụng Thread khởi tạo đầu tiên gọi là Thread sơ
cấp hay Thread chính.
1.3.5. Sử dụng Thread trong chương trình .NET.
Để sử dụng Thread trong .NET ta sử dụng namespace System.Threading.
Một số phương thức thường dùng:
Public Method
Name
Description (mô tả)
Abort () Kết thúc Thread.
Join ()
Buộc chương trình phải chờ cho thread kết thúc (Block) thì mới
thực hiện tiếp (các câu lệnh đứng sau Join).
Resume () Tiếp tục chạy thread đã tạm ngừng – suspended.
Sleep () Static method: tạm dừng thread trong một khoảng thời gian.
Start ()
Bắt đầu chạy (khởi động) một thread. Sau khi gọi phương thức
này, trạng thái của thread chuyển từ trạng thái hiện hành sang
Running.
Suspend ()

Tạm ngưng thread. (phương thức này được loại khỏi phiên bản
VS.NET 2005)
Trang 18
Một số thuộc tính thường dùng:
Name Description (mô tả)
CurrentThread This static property: trả về thread hiện hành đang chạy.
IsAlive Trả về giá trị cho biết trạng thái thực thi của thread hiện hành.
IsBackground
Sets or gets giá trị cho biết là thread là background hay
foreground thread.
IsThreadPoolThread
Gets a value indicating whether a thread is part of a thread
pool.
Priority
Sets or gets giá trị để chỉ định độ ưu tiên (dành nhiều hay ít
CPU cho thread). Cao nhất là 4, thấp nhất là 0.
ThreadState Lấy về trạng thái của thread (đang dừng, hay đang chạy…).
1.3.6. Sử dụng Threadpool trong các chương trình .Net.
Method (phương pháp) Description (Mô tả)
BindHandle ()
Binds an operating system handle to the
thread pool.
GetAvailableThreads()
Gets the number of worker threads
available for use in the thread pool.
GetMaxThreads ()
Gets the maximum number of worker
threads available in the thread pool.
QueueUserWorkItem ()
Queues a user delegate waiting for a

WaitHandle object.
UnsafeQueueUserWorkItem ()
Queues an unsafe user delegate to the
thread pool but does not propagate the
calling stack onto the worker thread.
UnsafeRegisterWaitForSingleObject ()
Registers an unsafe delegate waiting for
a WaitHandle object.
Trang 19
CHƯƠNG 2: XÂY DỰNG GIẢI PHÁP
2.1 Một số phương thức sử dụng trong chương trình.
Phương thức gửi file, phương thức này gửi file từ client tới server, với tham số đầu vào
là file cần gửi, lấy địa chỉ IP nhập vào, khởi tạo socket, rồi gửi file tới server
public void SendFile(string fileName)
{
try
{
//lay dia chi IP tren textbox
IPAddress[] ipAddress = Dns.GetHostAddresses(txtDiaChiIP.Text);
IPEndPoint ipEnd = new IPEndPoint(ipAddress[0], 5656);
//tao socket
Socket clientSock = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.IP);
string filePath = "";
//tao duong dan cho file voi ky tu /
fileName = fileName.Replace("\\", "/");
while (fileName.IndexOf("/") > -1)
{
filePath += fileName.Substring(0, fileName.IndexOf("/") +
1);

fileName = fileName.Substring(fileName.IndexOf("/") + 1);
}
byte[] fileNameByte = Encoding.ASCII.GetBytes(fileName);
if (fileNameByte.Length > 850 * 1024)
{
curMsg = "File size is more than 850kb, please try with
small file.";
return;
}
curMsg = "Buffering ";
byte[] fileData = File.ReadAllBytes(filePath + fileName);
byte[] clientData = new byte[4 + fileNameByte.Length +
fileData.Length];
byte[] fileNameLen =
BitConverter.GetBytes(fileNameByte.Length);
fileNameLen.CopyTo(clientData, 0);
fileNameByte.CopyTo(clientData, 4);
fileData.CopyTo(clientData, 4 + fileNameByte.Length);
curMsg = "Connection to server ";
clientSock.Connect(ipEnd);
Trang 20
curMsg = "File sending ";
clientSock.Send(clientData);
curMsg = "Disconnecting ";
clientSock.Close();
curMsg = "File transferred.";
}
catch (Exception ex)
{
if (ex.Message == "No connection could be made because the

target machine actively refused it")
curMsg = "File Sending fail. Because server not running.";
else
curMsg = "File Sending fail." + ex.Message;
}
}
Phương thức nhận file, phương thức này khởi động server, chờ client kết nối tới và
nhận file
class FTServerCode
{
IPEndPoint ipEnd;
Socket sock;
public FTServerCode()
{
ipEnd = new IPEndPoint(IPAddress.Any, 5656);
//tao 1 socket
sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
ProtocolType.IP);
sock.Bind(ipEnd);
}
public static string receivedPath;
public static string curMsg = "Stopped";
public void StartServer()
{
try
{
curMsg = "Starting ";
sock.Listen(100);
curMsg = "Running and waiting to receive file.";
Socket clientSock = sock.Accept();//chap nhan ket noi tu client

byte[] clientData = new byte[1024 * 5000];
//nhan data tu client
int receivedBytesLen = clientSock.Receive(clientData);
curMsg = "Receiving data ";
int fileNameLen = BitConverter.ToInt32(clientData, 0);
string fileName = Encoding.ASCII.GetString(clientData, 4,
fileNameLen);
//ghi file
BinaryWriter bWrite = new BinaryWriter(File.Open(receivedPath +
"/" + fileName, FileMode.Append)); ;
bWrite.Write(clientData, 4 + fileNameLen, receivedBytesLen - 4
- fileNameLen);
curMsg = "Saving file ";
Trang 21
bWrite.Close();
clientSock.Close();
curMsg = "Reeived & Saved file; Server Stopped.";
}
catch (Exception ex)
{
curMsg = "File Receving error.";
}
}
2.2 Một số giao diện chính của chương trình:
Giao diện nén file
Server
Client
Trang 22
2.3 Thuật toán Huffman.
Trong khoa học máy tính và lý thuyết thông tin, mã hóa Huffman là một thuật

toán mã hóa dùng để nén dữ liệu. Nó dựa trên bảng tần suất xuất hiện các kí tự cần mã
hóa để xây dựng một bộ mã nhị phân cho các kí tự đó sao cho dung lượng (số bít) sau
khi mã hóa là nhỏ nhất
Trong khoa học máy tính và lý thuyết thông tin, mã hóa Huffman là một thuật
toán mã hóa dùng để nén dữ liệu. Nó dựa trên bảng tần suất xuất hiện các kí tự cần mã
hóa để xây dựng một bộ mã nhị phân cho các kí tự đó sao cho dung lượng (số bít) sau
khi mã hóa là nhỏ nhất (wikipedia.org).
Mã hóa dữ liệu trong máy tính.
Để mã hóa các kí hiệu (bao gồm kí tự, chữ số, …) trong máy tính, ta thay chúng
bằng các xâu nhị phân, được gọi là từ mã của kí hiệu đó.
Ví dụ bộ mã ASCII ra đời năm 1967, mã hóa cho 256 kí hiệu là biểu diễn nhị
phân của các số từ 0 đến 255, mỗi từ mã gồm 8 bit. Trong ASCII từ mã của kí tự “a” là
1100001, của kí tự “A” là 1000001. Trong cách mã hóa này các từ mã của tất cả 256 kí
hiệu có độ dài bằng nhau (mỗi từ mã 8 bít). Nó được gọi là mã hóa với độ dài không
đổi.
Khi mã hóa một tài liệu có thể không sử dụng đến tất cả 256 kí hiệu. Hơn nữa
trong tài liệu chữ cái “a” chỉ có thể xuất hiện 1000000 lần còn chữ cái “A” có thể chỉ
xuất hiện 2, 3 lần. Như vậy ta có thể không cần dùng đủ 8 bit để mã hóa cho một ký
hiệu, hơn nữa độ dài (số bit) dành cho mỗi kí hiệu có thể khác nhau, kí hiệu nào xuất
hiện nhiều lần thì nên dùng số bit ít, ký hiệu nào xuất hiện ít thì có thể mã hóa bằng từ
Trang 23
mã dài hơn. Như vậy ta có việc mã hóa với độ dài thay đổi. Để phân biệt được xâu bít
nào là mã hóa của ký hiệu nào, một trong các giải pháp là dùng các dấu phẩy (“,”)
hoặc một kí hiệu quy ước nào đó để tách từ mã của các kí tự đứng cạnh nhau. Nhưng
như thế số các dấu phẩy sẽ chiếm một không gian đáng kể trong bản mã. Một cách giải
quyết khác dẫn đến khái niệm mã phi tiền tố.
Mã phi tiền tố.
Mã phi tiền tố là bộ các từ mã của một tập hợp các kí hiệu sao cho từ mã của mỗi
ký hiệu không là tiền tố (phần đầu) của từ mã một ký hiệu khác trong bộ mã ấy.
Ví dụ có từ “CNTT” gồm 3 chữ cái là C,N,T. Nếu dùng cách mã hóa với độ dài không

đổi thì mỗi chữ cái được mã hóa tối thiểu là 2 bit chẳng hạn C=00, N=01, T=10. Khi
đó xâu được mã hóa là 00011010. Nếu mã hóa C=0, N=01, T=11 thì bộ từ mã này
không là mã phi tiền tố vì từ mã của chữ C là tiền tố của từ mã của N. Để mã hóa cả từ
này ta phải đặt dấu ngăn cách vào giữa các từ mã 0,01,10,10. Nếu mã hóa C=0, N=10,
T=11 thì bộ mã này là mã phi tiền tố. Với bộ mã phi tiền tố này thì xâu được mã hóa là
0101111.
Mã Huffman.
Mỗi mã phi tiền tố có thể biểu diễn bởi một cây nhị phân T mà mỗi lá của nó
tương ứng với một chữ cái và cạnh của nó được gán cho một trong hai số 0 hoặc 1. Mã
của một chữ cái c là một dãy nhị phân gồm các số gán cho các cạnh trên đường đi từ
gốc đến lá tương ứng với c.
Bài toán: Tìm cách mã hóa tối ưu, tức là tìm cây nhị phân T làm tối thiểu hóa
tổng độ dài có trọng số
B(T) = ∑ f(c) depth(c)
trong đó f(c) và depth(c) là tần số và độ dài đường đi từ gốc đến lá tương ứng với
ký tự c.
Ý tưởng: Chữ cái có tần suất nhỏ hơn cần được gán cho lá có khoảng cách đến
gốc là lớn hơn, chữ cái có tần suất xuất hiện lớn hơn cần được gán cho nút gần gốc
hơn.
Trang 24
Thuật toán xây dựng cây mã Huffman.
Procedure Huffman(C,f)
Begin
Duyệt khi đến hết C
Begin
x, y ← hai chữ cái có tần suất nhỏ nhất trong C;
Tạo nút p với hai con x, y;
f(p):= f(x) + f(y);
C ← C \ {x, y} U {p};
end;

End;
Trong đó: C là bảng các chữ cái, n là số chữ cái có trong C, f là bảng tần suất
xuất hiện các chữ cái trong C.
Ví dụ: Xây dựng cây mã Huffman với bảng tần suất dưới đây:
C T D L G
23 61 43 70 12
Quá trình xây dựng cây Huffman diễn ra như sau:
Trang 25

×