Giao thức FTP là một giao thức trao đổi file tin cậy và khá phổ biến, thường được sử dụng để trao đổi file giữa người dùng cuối với các máy chủ FTP, là công cụ không thể thiếu đối với cá
Trang 1LỜI CẢM ƠN
Trước tiên, em xin chân thành cảm ơn đến thầy giáo Th.S Trần Hồng Anh
đã tận tình hướng dẫn em trong thời gian thực hiện đồ án tốt nghiệp này
Em xin chân thành cảm ơn các thầy cô giáo trường Đại học Công Nghệ Thông Tin & Truyền Thông – ĐH Thái Nguyên đã truyền thụ kiến thức cho em trong năm năm học tập tại trường
Tôi xin gửi lời cảm ơn đến tất cả bạn bè đã động viên giúp đỡ trong quá trình học tập cũng như trong thời gian thực hiện đồ án tốt nghiệp
Cuối cùng, em xin kính chúc thầy cô sức khỏe, tiếp tục đạt được nhiều thành tích trong giảng dạy cũng như trong nghiên cứu khoa học và sự nghiệp giáo dục
Thái Nguyên tháng 6 năm 2012 Sinh viên: Nguyễn Thành Luân
Trang 2LỜI NÓI ĐẦU
Sự phát triển mạnh mẽ của công nghệ thông tin trong những năm gần đây đã tạo nên những thay đổi to lớn đối với cuộc con người Nó ngày càng khẳng định được vai trò của mình trong sự phát triển chung của xã hội.Mạng viễn thông mà tiêu biểu là Internet đã kết nối mọi người trên toàn thế giới, cung cấp đa dịch vụ từ trò chuyện trực tuyến, thư điện tử, điện thoai Internet, hội nghị truyền hình, các thông tin khoa học kinh tế, giáo dục…Truy cập Internet trở thành nhu cầu quen thuộc đối với mọi người
Vấn đề trao đổi file là không thể thiếu đối với người dùng đầu cuối Giao thức FTP là một giao thức trao đổi file tin cậy và khá phổ biến, thường được sử dụng để trao đổi file giữa người dùng cuối với các máy chủ FTP, là công cụ không thể thiếu đối với các lập trình viên phát triển web hay người dùng mới muốn xây tự thiết lập một trang web cho mình
Xuất phát từ thực tế đó em thực hiện đề tài: Xây dựng ứng dụng FTP Client
sử dụng giao thức FTP.
Nội dung gồm 3 phần :
- Chương 1: Tổng quan về lập trình mạng trong C#
- Chương 2: Giao thức FTP - File transfer protocol
- Chương 3: Xây dựng chương trình
Đề tài được thực hiện trong thời gian ngắn, cũng như khả năng còn hạn chế nên chắc chắn không tránh khỏi những thiếu xót Em rất mong nhận được sự chỉ bảo
từ thầy cô cũng như những đóng góp của các bạn
Trang 3DANH MỤC TỪ VIẾT TẮT VÀ THUẬT NGỮ
FTP File Transfer Protocol: Giao thức truyền file
TCP Transmission Control Protocol: Giao thức điều khiển truyền vận FTP Server Máy chủ FTP : Trình chủ
FTP Client Máy khách : Trình khách.
Server -FTP Process Tiến trình máy chủ FTP.
Server-PI Server Protocol Interpreter
Server-DTP Server DataTransfer Process
User-PI User Protocol Interpreter
User-DTP User Data Transfer Process
Username Tên người dùng
Trang 4MỤC LỤC
Trang 5DANH MỤC HÌNH
Trang 6DANH MỤC CÁC BẢNG
Trang 7CHƯƠNG 1 TỔNG QUAN VỀ LẬP TRÌNH MẠNG TRONG C#
1.1 Sơ lược về lập trình Socket
1.1.1 Khái niệm địa chỉ và cổng (Address & 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 (ví dụ 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)
Trang 8Để 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: "192.168.1.1", "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 với khai báo “byte[] DiaChi = new byte[4];”, ta
- 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
- 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
Trong 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 …
Bảng 1.1: Các thành phần của lớp IpAddress
Thành viên Static Mô tả
Server phải lắng nghe các hoạt động của Client trên tất cả các Card mạng Thuộc tính này chỉ đọc
Broadcast Cung cấp một địa chỉ IP quảng bá (Broadcast, thường là
255.255.255.255), ở dạng số long
Loopback Trả về một địa chỉ IP lặp (IP Loopback, ví dụ 127.0.0.1)
AddressFamily Trả về họ địa chỉ của địa chỉ IP hiện hành Nếu địa chỉ ở
dạng IPv4 thì kết quả là Internetwork, và InternetworkV6
1 (Byte 0) 1 168 192 (Byte 3)
Trang 9nếu là địa chỉ IPv6
IPAddress(Int64) Tạo địa chỉ IP từ một số long
IPAddress(Byte[]) Tạo địa chỉ IP từ một mảng Byte
GetAddressByte () Chuyển địa chỉ thành mảng Byte
HostToNetworkOrd
er()
Đảo thứ tự Byte của một số cho đúng với thứ tự Byte trong địa chỉ IPAddress
IsLoopback() Cho biết địa chỉ có phải là địa chỉ lặp hay không?
- Ví dụ 1: Kiểm tra xem 192.168.1.300 có phải là địa chỉ IP hợp lệ không
private void KiemTra()
{
String Ip1 = "127.0.0.1";
String Ip2 = "999.0.0.1";
MessageBox.Show(IPAddress.TryParse(Ip1, new IPAddress(0)));
MessageBox.Show (IPAddress.TryParse(Ip2, new IPAddress(1)));
Trang 10thông tin Lớp IPAddress mới chỉ cung cấp cho ta một vế là địa chỉ IP (IPAddress), như vậy vẫn 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…
Bảng 1.2: Các thành viên của lớp IpEndPoint
Phương thức khởi tạo Mô tả
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
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ử
Trang 11thứ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 namesapce System.Net.Sockets)
đóng gói các chức năng của giao thức UDP
Bảng 1.3: Các thành viên của lớp UDPClient
Phương thức khởi tạo Mô tả
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 (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ó
BeginReceive () Nhận dữ liệu Không đồng bộ từ máy ở xa
EndReceive () Kết thúc nhận dữ liệu không đồng bộ ở trên
Receive (ref IPEndPoint) Nhận dữ liệu (đồng bộ) do máy ở xa gửi (Đồng
bộ có nghĩa là các lệnh ngay sau lệnh Receive chỉ được thực thi nếu Receive đã nhận được dữ liệu
về Còn nếu nó chưa nhận được – dù chỉ một chút – thì nó vẫn cứ chờ (blocking))
Trang 121.1.5 Lớp TCP (TCPClient)
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 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
Bảng 1.4: Các thành phần của lớp TcpClient
Phương thức khởi tạo Mô tả
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(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
Các thuộc tính Mô tả
Available Cho biết số byte đã nhận về từ mạng và có sẵn để đọc
Connected Trạng thái cho biết đã kết nối được đến Server hay chưa?
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 để 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ì
Trang 13ta 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:
Bước 1: Tạo một đối tượng TcpClient
Bước 2: Kết nối đến máy chủ (Server) dùng phương thức Connect.
Bước 3: Tạo 2 đối tượng StreamReader (Receive)và StreamWriter (Send) và
"nối" với GetStream của cpPClient.
Bảng 1.5: Các thành phần của lớp TcpListener
Phương thức khởi tạo Mô tả
TcpListener ( Int32) Tạo một TcpListener và lắng nghe tại cổng chỉ
Trang 14đến tại địa chỉ IP và cổng chỉ định
AcceptSocket( ) Chấp nhận một yêu cầu kết nối đang chờ
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 lệnh này cho đến khi nào có một kết nối đến – “Blocking”)
Pending() Cho biết liệu có kết nối nào đang chờ đợi không
Start() Bắt đầu lắng nghe các yêu cầu kết nối
1.2 Sơ lược về lập trình đa luồng
1.2.1 Khái niệm Luồng (Thread)
Mộtluồ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
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 ta 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
Bảng 1.6: 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)
Moniter Lớp này cung cấp việc đồng bộ hóa các đối tượng luồng
sử dụng khóa chốt (lock) và tín hiệu chờ (wait signal)
Mutex Lớp này cung cấp việc đồng bộ hóa sơ đẳng có thể
được dùng đối với inter process synchronization
Thread Lớp này tượng trưng cho một luồng được thi hành trong
Trang 15lòng Common Language Runtime Sử dụng lớp này có khả năng bổ sung những luồng khác trong cùng AppDomain.
ThreadPool Lớp này quản lý những luồng có liên hệ với nhau trong
cùng một Process nào đó
Timer Cho biết một delegate có thể được triệu gọi vào một lúc
được khai báo nào đó Tác vụ wait được thi hành bởi luồng trong thread pool
WaitHandle Lớp này tượng trưng cho tất cả các đối tượng đồng bộ
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 đó
phải được thi hành đầu tiên khi một luồng bắt đầu
TimerCallBack 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
1.2.2.1 Lớp Thread
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 định nghĩa một số phương thức thực thi (cả static lẫn shared) cho phép lập trình viê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 đó
Bảng 1.7: 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
hành đối với domain hiện hành trong luồng
GetDomain()
GetDomainID()
Đi lấy một qui chiếu về AppDomain hiện hành (hoặc mã nhận diện ID của domain này) mà luồng hiện đang chạy trên đó
Trang 16Sleep() 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.
Bảng 1.8: Các thành viên cấp đối tượng của lớp Thread
Các lớp thành viên Mô tả
IsAlive 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
mang tính thân thiện đối với luồng
Priority Đi lấy hoặc đặt để ưu tiên của 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, SuspendRequested, AbortRequested, Stopped).
Interrup() 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
Start() Cho bắt đầu thi hành luồng được khai báo bởi
delegate ThreadStart
Suspend() Cho ngưng chạy một luồng Nếu luồng đã bị ngưng
rồi, một triệu gọi hàm Suspend() sẽ không có tác
dụng
Trang 171.2.2.2 Thao tác với luồng
Luồng được thao tác bằng cách dùng lớp Thread nằm trong Namespace
System.Threading Một thể hiện của luồng đại diện cho một luồng Ta có thể tạo các luồng khác bằng cách khởi tạo một đối tượng Thread
Mỗi lần ta bắt đầu một luồng khác, ta cũng có thể đình chỉ, hồi phục hay bỏ qua nó Đình chỉ nghĩa là cho luồng đó ngủ (sleep) - hay không chạy trong một khoảng thời gian Sau đó nó có thể được phục hồi, nghĩa là trả nó về thời diểm mà
nó bị định chỉ Nếu luồng được bỏ, nó dừng chạy Window sẽ hủy tất cả dữ liệu mà liên hệ đến luồng đó, để luồng không thể được bắt đầu lại
1.2.3 Đồng bộ hóa (Synchronization) trong lập trình đa luồng
1.2.3.1 Đồng bộ hóa
Đôi khi ta muốn điều khiển việc truy cập vào một tài nguyên, chẳng hạn các thuộc tính hoặc các hàm của một đối tượng, và muốn chỉ một tiến trình được phép thay đổi hoặc sử dụng tài nguyên đó Việc đồng bộ hóa được thể hiện thông qua một 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 tiến trình đi trước chưa xong công việc
Common Language Runtime sẽ cung cấp một cơ chế đồng bộ hóa bằng cách
sử dụng: lệnh lock Đầu tiên, ta mô phỏng một tài nguyên đượ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ề 0:
int counter = 0;
Bài toán được đặt ra ở đây như sau: luồng thứ nhất sẽ đọc giá 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,
Trang 182, 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.
Đoạn mã của chương trình như sau:
private int counter = 0;
static void Main(string[] args)
Console.WriteLine("Start thread {0}", t1.Name);
Thread t2 = new Thread(new ThreadStart(Incrementer));
t2.IsBackground = true;
t2.Name = "Thread Two";
Trang 20Hình 1.1: Kết quả chương trình không sử dụng đồ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
Để có được kết quả như mong muốn, ta sẽ sửa hàm Incrementer lại như sau:
Trang 21Kết quả thu được sẽ là:
Hình 1.2: Kết quả chương trình sử dụng đồng bộ hóa
Việc đồng bộ các luồng là quan trọng trong các ứng dụng đa luồng Tuy nhiên
có một số lỗi nhỏ và khó kiểm soát có thể xuất hiện cụ thể là deadlock và race condition
Trang 24lock (B) {
// do something lock (A)
{ // do something }
}
Có thể xảy ra biến cố sau: luồng đầu tiên yêu cầu một lock trên A, trong khi vào cùng thời điểm đó luồng thứ hai yêu cầu lock trên B Một khoảng thời gian ngắn sau, luồng A gặp câu lệnh lock(B), và ngay lập tức bước vào trạng thái ngủ, đợi cho lock trên B được giải phóng Và tương tự sau đó, luồng thứ hai gặp câu lệnh
lock(A) và cũng rơi vào trạng thái ngủ chờ cho đến khi lock trên A được giải
phóng Không may, lock trên A sẽ không bao giờ được giải phóng bởi vì luồng đầu tiên mà đã lock trên A đang ngủ và không thức dậy cho đến khi lock trên B được
giải phóng điều này cũng không thể xảy ra cho đến khi nào luồng thứ hai thức dậy Kết quả là deadlock Cả hai luồng đều không làm gì cả, đợi lẫn nhau để giải phóng lock Loại lỗi này làm toàn ứng dụng bị treo, ta phải dùng Task Manager để hủy nó.Deadlock có thể được tránh nếu cả hai luồng yêu cầu lock trên đối tượng theo cùng thứ tự Trong ví dụ trên nếu luồng thứ hai yêu cầu lock cùng thứ tự với luồng
đầu, A đầu tiên rồi tới b thì những luồng mà lock trên a đầu sẽ hoàn thành nhiệm vụ
của nó sau đó các luồng khác sẽ bắt đầu
1.2.3.3 Race condition
Race conditionít kh dừng việc thực thi của tiến trình , nhưng nó có thể dẫn đến việc dữ liệu bị lỗi Nói chung nó xuất hiện khi vài luồng cố gắng truy nhập vào cùng một dữ liệu và không quan tâm đến các luồng khác làm gì Ta có thể xem ví dụ sau :
Trang 25Giả sử ta có một mảng các đối tượng, mỗi phần tử cần được xử lí bằng một cách nào đó, và ta có một số luồng giữa chúng làm tiến trình này Ta có thể có một đối tuợng gọi là ArrayController chứa mảng đối tượng và một số int chỉ định số phẩn tử được xử lí tacó phương thức:
int GetObject(int index) {
// trả về đối tượng với chỉ mục được cho }
Và thuộc tính read/write
int ObjectsProcessed {
// chỉ định bao nhiêu đối tượng được xử lí }
Bây giờ mỗi luồng mà dùng để xử lí các đối tượng có thể thi hành đoạn mã sau:
lock(ArrayController) {
int nextIndex = ArrayController.ObjectsProcessed;
Console.WriteLine(”Object to be processed next is ” + NextIndex); ++ArrayController.ObjectsProcessed;
object next = ArrayController.GetObject();
} ProcessObject(next);
Nếu ta muốn tài nguyên không bị giữ quá lâu , ta có thể không giữ lock trên ArrayController trong khi ta đang trình bày thông điệp người dùng Do đó ta viết lại đoạn mã trên:
lock(ArrayController) {
Trang 26int nextIndex = ArrayController.ObjectsProcessed;
} Console.WriteLine(”Object to be processed next is ” + nextIndex); lock(ArrayController)
{ ++ArrayController.ObjectsProcessed;
object next = ArrayController.GetObject();
} ProcessObject(next);
Ta có thể gặp một vấn đề Nếu một luồng lấy lấy đối tưọng (đối tượng thứ 11 trong mảng) và đi tới trình bày thông điệp nói về việc xử lí đối tượng này Trong khi
đó luồng thứ hai cũng bắt đầu thi hành cũng đoạn mã gọi ObjectProcessed, và quyết định đối tượng xử lí kế tiếp là đối tượng thứ 11, bởi vì luồng đầu tiên vẫn chưa được cập nhật
ArrayController.ObjectsProcessed trong khi luồng thứ hai đang viết đến màn hình rằng bây giờ nó sẽ xử lí đối tượng thứ 11, luồng đầu tiên yêu cầu một lock khác trên ArrayController và bên trong lock này tăng ObjectsProcessed Tuy nhiên, nó quá chậm Cả hai luồng đều đang xử lí cùng một đối tượng và trường hợp này ta gọi
là Race Condition
1.3 Lớp FtpWebRequest
Từ NET Framework 2.0, Microsoft đã bổ sung thêm các lớp hỗ trợ cho lập trình mạng trong đó có hỗ trợ FTP Server Các lớp này nằm trong NameSpace System.Net.Lập trình viên có thể xây dựng chương trình tải tập tin từ một máy chủ FTP bằng cách sử dụng lớp WebClient
1.3.1 Các thành phần trong FtpWebRequest
AuthenticationLevel Chỉ ra mức độ xác thực và mạo danh
CachePolicy Trả về hoặc thiết lập yêu cầu cache
ClientCertificates Thiết lập một kết nối mã hóa đến FTP
ConnectionGroupName Đặt tên cho nhóm kết nối
Trang 27ContentLength Trả về hoặc thiết lập giá trị được bỏ qua bởi lớp FtpWebRequest
ContentOffset Trả về hoặc thiết lập một byte trong tập tin được tải về.
ContentType Luôn luôn cùng kiểu không hỗ trợ ngoại lệ
Credentials Thông tin dùng để giao tiếp với máy chủ
DefaultCachePolicy Xác định bộ nhớ cache mặc định chính sách cho tất cả các yêu cầu
FTP.
EnableSSL Trả về hoặc tạo một Boolean quy định rằng một kết nối SSL được sử
dụng.
Headers Là tiêu đề nhận từ một đối tượng nào đó
ImpersonationLevel Đặt mức mạo danh cho yêu cầu hiện tại.(thừa kế từ WebRequest )
Keepalive Trả về hoặc thiết lập một giá trị Boolean điều khiên kết nối đến máy
chủ FTP được đóng lại sau khi yêu cầu hoàn tất.
Method Đặt lệnh để gửi đến máy chủ FTP
PreAuthenticate Luôn luôn cùng kiểu không hỗ trợ ngoại lệ
Proxy Đặt proxy và được sử dụng để giao tiếp với máy chủ FTP.
ReadWriteTimeOut Nhận hoặc lập một thời gian chờ khi đọc từ hay văn bản cho luồng.
Rename To Đặt tên mới của một tập tin được đổi tên.
RequestUri Trả về URI được yêu cầu
ServicePoint Trả về đối tượng ServicePoint sử dụng để kết nối đến máy chủ FTP.
TimeOut Thời gian chờ yêu cầu tính bằng mili giây
UseBinary Nhận hoặc thiết lập một giá trị Boolean chỉ định kiểu dữ liệu để
truyền tải tập tin.
UseDefaultCredenticals Luôn luôn cùng kiểu không hỗ trợ ngoại lệ
UsePassive Là hành vi của một ứng dụng xử lý dữ liệu của client chuyển đến
1.3.2 Các phương thức
Abort Hủy một FTP không đồng bộ hoạt động.
BeginGetRequestStream Bắt đầu mở không đồng bộ luồng nội dung yêu cầu ghi
BeginGetResponse Gửi một yêu cầu và nhận được đáp ứng từ máy chủ FTP không
đồng bộ.
CreateObjRef Tạo ra một đối tượng có chứa tất cả các thông tin liên quan cần
thiết để tạo ra một proxy được sử dụng để giao tiếp với một đối tượng từ xa.
EndGetRequestStream Kết thúc một hoạt động không đồng bộ chưa bắt đầu với
BeginGetRequestStream.
EndGetResponse Kết thúc một hoạt động không đồng bộ bắt đầu với
BeginGetResponse
Equal(Object) Xác định xem các quy định đối tượng vớiđối tượng hiện thời.
Finalize Cho phép một đối tượng sử dụng tài nguyên trống và thực hiện
các hoạt động dọn dẹp khác trước khi nó được thu hồi bởi các mục đã chọn
GetHashCode Phục vụ như một hàm băm cho một kiểu cụ thể.
GetLifetimeService Trả về dịch vụ hiện tại đối tượng điều khiển chính sách cho
trường hợp này
GetObjectData Populates một SerializationInfo với các dữ liệu cần thiết để
tuần tự hóa các đối tượng đích
GetReQuestStream Lấy các dòng sử dụng để upload dữ liệu vào một máy chủ FTP.
GetResponse Trả về đáp ứng từ máy chủ FTP
GetType Các loại chỉ định hiện tại.
Trang 28InitializeLifetimeService Dùn để kiểm soát các chính sách đời cho trường hợp.
MemberwiseClone() Tạo một bản sao của đối tượng hiện hành
MemberwiseClone(Boolean) Tạo một bản sao hiện tại của đối tượng
ToString Trả về một chuỗi đại diện cho đối tượng hiện tại.
Trang 29CHƯƠNG 2 GIAO THỨC FTP 2.1 Giới thiệu về giao thức FTP
FTP là viết tắt của File Transfer Protocol – giao thức truyền file FTP là một giao thức truyền file trên mạng dựa trên chuẩn TCP nên rất đáng tin cậy Để hoạt động, FTP cần có hai máy tính, một máy chủ FTP (FTP Server) và một máy khách (Client) Máy chủ FTP dùng chạy phần mềm cung cấp dịch vụ FTP gọi là trình chủ, lắng nghe yêu cầu về dịch vụ của các máy khách Máy khách chạy phần mềm FTP dành cho người sử dụng dịch vụ, gọi là trình khách Khi hai máy đã kết nối với nhau, máy khách có thể xử lý một số thao tác về tập tin, như tải tập tin lên máy chủ, tải tập tin từ máy chủ xuống máy của mình, đổi tên của tập tin, hoặc xóa tập tin ở máy chủ Vì giao thức FTP là một giao thức chuẩn công khai, cho nên bất cứ một công ty phần mềm nào, hay một lập trình viên nào cũng có thể viết trình chủhoặc trình khách FTP Hầu như bất cứ một nền tảng hệ điều hành máy tính nào cũng hỗ trợ giao thức FTP
FTP thường chạy trên cổng 20 và 21, và chỉ chạy trên nền FTP FTP Server lắng nghe các yêu cầu kết nối từ các FTP Client trên cổng 21 Kênh kết nối trên cổng 21 này gọi là kênh điều khiển, cho phép các dòng lệnh được truyền qua, còn kênh dùng để truyền dữ liệu là một kênh khác
Mục đích của giao thức FTP:
- Khuyến khích việc dùng chung tập tin (như chương trình ứng dụng
máy tính hoặc dữ liệu)
- Khuyến khích việc sử dụng máy tính ở xa một cách gián tiếp / ngấm
ngầm (implicit)
- Giúp che đậy sự khác biệt về hệ thống lưu trữ tập tin giữa các máy
chủ.Người dùng không cần quan tâm đến những sự khác biệt của chúng
- Truyền tải dữ liệu một cách đáng tin cậy và có hiệu quả cao
Trang 302.2 Mô hình hoạt dộng của giao thức FTP
Hình 2.1: Mô hình hoạt động của giao thức FTP
Giao thức FTP được mô tả một cách đơn giản thông qua mô hình hoạt động của FTP Mô hình này chỉ ra các nguyên tắc mà một thiết bị phải tuân theo khi tham gia vào quá trình trao đổi file, cũng như về hai kênh thông tin cần phải thiết lập giữa các thiết bị đó Nó cũng mô tả các thành phần của FTP được dùng để quản lý các
Trang 31kênh này ở cả hai phía – truyền và nhận Do đó, mô hình này tạo cho ta một khởi điểm lý tưởng để xem xét hoạt động của FTP ở mức khái quát.
- Tiến trình Server-FTP và User-FTP
FTP là một giao thức dạng client/server truyền thống, tuy nhiên thuật ngữ client thông thường được thay thế bằng thuật ngữ user – người dùng – do thực tế
là người sử dụng mới là đối tượng trực tiếp thao tác các lệnh FTP trên máy client
Bộ phần mềm FTP được cài đặt trên một thiết bị được gọi là một tiến trình Phần mềm FTP được cài đặt trên máy Server được gọi là tiến trình Server-FTP, và phần trên máy client được gọi là tiến trình User-FTP
- Kênh điều khiển và kênh dữ liệu trong FTP
Mặc dù giao thức FTP sử dụng kết nối TCP, nhưng nó không chỉ dùng một kênh TCP như phần lớn các giao thức truyền thông khác Mô hình FTP chia quá trình truyền thông giữa bộ phận Server với bộ phận client ra làm hai kênh logic:
+ Kênh điều khiển: đây là kênh logic TCP được dùng để khởi tạo một phiên kết nối FTP Nó được duy trì xuyên suốt phiên kết nối FTP và được
sử dụng chỉ để truyền các thông tin điều khiển, như các lệnh và các hồi đáp trong FTP Nó không được dùng để truyền file
+ Kênh dữ liệu: Mỗi khi dữ liệu được truyền từ server tới client, một kênh kết nối TCP nhất định lại được khởi tạo giữa chúng Dữ liệu được truyền đi qua kênh kết nối này – do đó nó được gọi là kênh dữ liệu Khi tập tin được truyền xong, kênh này được ngắt Việc sử dụng các kênh riêng lẻ như vậy tạo ra sự linh hoạt trong việc truyền truyền dữ liệu – mà ta sẽ thấy trong các phần tiếp theo Tuy nhiên, nó cũng tạo cho FTP độ phức tạp nhất định
- Các tiến trình và thuật ngữ trong FTP
Do các chức năng điều khiển và dữ liệu sử dụng các kênh khác nhau, nên mô hình hoạt động của FTP cũng chia phần mềm trên mỗi thiết bị ra làm hai thành phần logic tương ứng với mỗi kênh Thành phần Protocol Interpreter (PI) là thành phần quản lý kênh điều khiển, với chức năng phát và nhận lệnh Thành phần Data
Trang 32server Ngoài ra, cung cấp cho tiến trình bên phía người dùng còn có thêm thành phần thứ ba là giao diện người dùng FTP - thành phần này không có ở phía server.
Do đó, có hai tiến trình xảy ra ở phía server, và ba tiến trình ở phía client Các tiến trình này được gắn với mô hình FTP để mô tả chi tiết hoạt động của giao thức FTP
- Các tiến trình phía server:
+ Server Protocol Interpreter (Server-PI): chịu trách nhiệm quản lý kênh điều khiển trên server Nó lắng nghe yêu cầu kết nối hướng tới từ users trên cổng dành riêng Khi kết nối đã được thiết lập, nó sẽ nhận lệnh từ phía User-PI, trả lời lại, và quản lý tiến trình truyền dữ liệu trên server
+ Server DataTransfer Process (Server-DTP): làm nhiệm vụ gửi hoặc nhận file từ bộ phận User-DTP Server-DTP vừa làm nhiệm thiết lập kết nối kênh
dữ liệu và lắng nghe một kết nối kênh dữ liệu từ user Nó tương tác với server file trên hệ thống cục bộ để đọc và chép file
- Các tiến trình phía client:
+ User Protocol Interpreter (User-PI): chịu trách nhiệm quản lý kênh điều khiển phía client Nó khởi tạo phiên kết nối FTP bằng việc phát ra yêu cầu tới phía Server-PI Khi kết nối đã được thiết lập, nó xử lý các lệnh nhận được trên giao diện người dùng, gửi chúng tới Server-PI, và nhận phản hồi trở lại Nó cũng quản
lý tiến trình User-DTP
+ User Data Transfer Process (User-DTP): là bộ phận DTP nằm ở phía người dùng, làm nhiệm vụ gửi hoặc nhận dữ liệu từ Server-DTP User-DTP có thể thiết lập hoặc lắng nghe yêu cầu kết nối kênh dữ liệu trên server Nó tương tác với thiết bị lưu trữ file phía client
+ User Interface: cung cấp giao diện xử lý cho người dùng Nó cho phép
sử dụng các lệnh đơn giản hướng người dùng, và cho phép người điều khiển phiên FTP theo dõi được các thông tin và kết quả xảy ra trong tiến trình
Trang 332.3 Thiết lập kênh điều khiển và chứng thực người dùng trong FTP
Mô hình hoạt động của FTP mô tả rõ các kênh dữ liệu và điều khiển được thiết lập giữa FTP client và FTP server Trước khi kết nối được sử dụng để thực sự truyền tập tin, kênh điều khiển cần phải được thiết lập Một tiến trình chỉ định sau
đó được dùng để tạo kết nối và tạo ra phiên FTP giữa các thiết bị để truyền tập tin.Như trong các giao thức client/server khác, FTP server tuân theo một luật passive trong kênh điều khiển Bộ phận Server Protocol Interpreter (Server-PI) sẽ lắng nghe cổng TCP dành riêng cho kết nối FTP là cổng 21 Phía User-PI sẽ tạo kết nối bằng việc mở một kết nối TCP từ thiết bị người dùng tới server trên cổng
đó Nó sử dụng một cổng bất kỳ làm cổng nguồn trong phiên kết nối TCP
Khi TCP đã được cài đặt xong, kênh điều khiển giữa các thiết bị sẽ được thiết lập, cho phép các lệnh được truyền từ User-PI tới Server-PI, và Server-PI sẽtrả lại kết quả là các mã thông báo Bước đầu tiên sau khi kênh đã đi vào hoạt động là bước đăng nhập của người dùng (login sequence) Bước này có hai mục đích:
+ Access Control - Điều khiển truy cập: quá trình chứng thực cho phép hạn chế truy cập tới server với những người dùng nhất định Nó cũng cho phép server điều khiển loại truy cập như thế nào đối với từng người dùng
+ Resource Selection - Chọn nguồn cung cấp: Bằng việc nhận dạng người dùng tạo kết nối, FTP server có thể đưa ra quyết định sẽ cung cấp những nguồn nào cho người dùng đã được nhận dạng đó
2.3.1 Trình tự truy cập và chứng thực FTP
Quá trình chứng thực trong FTP thì khá đơn giản, người dùng chỉ cần cung cấp username/password được cung cấp bới FTP Server
Trình tự của việc chứng thực như sau:
- Người dùng gửi một username từ User-PI tới Server-PI bằng lệnh USER Sau đó password của người dùng được gửi đi bằng lệnh PASS
- Server kiểm tra tên người dùng và password trong database người dùng của nó Nếu người dùng hợp lệ, server sẽ gửi trả một thông báo tới
Trang 34server yêu cầu người dùng thực hiện lại việc chứng thực Sau một số lần chứng thực sai nhất định, server sẽ ngắt kết nối.
Giả sử quá trình chứng thực đã thành công, server sau đó sẽ thiết lập kết nối
để cho phép từng loại truy cập đối với người dùng được cấp quyền Một số người dùng chỉ có thể truy cập vào một số tập tinh nhất định, hoặc vào một số loại tập tin nhất định Một số server có thể cấp quyền cho một số người dùng đọc và viết lên server, trong khi chỉ cho phép đọc đối với những người dùng khác Người quản trị mạng có thể nhờ đó mà đáp ứng đúng các nhu cầu truy cập FTP
Một khi kết nối đã được thiết lập, Server có thể thực hiện các lựa chọn tài nguyên dựa vào nhận diện người dùng Ví dụ: trên một hệ thống nhiều người dùng, người quản trị có thể thiết lập FTP để khi có bất cứ người dùng nào kết nối tới, anh ta sẽ tự động được đưa tới "home directory" của chính anh ta Lệnh tùy chọn ACCT (account) cũng cho phép người dùng chọn một tài khoản cá nhân nào
đó nếu như anh ta có nhiều hơn một tài khoản
2.3.2 Mở rộng về bảo mật FTP
Giống như phần lớn các giao thức cũ, phương pháp đăng nhập đơn giản của FTP là một sự kế thừa từ những giao thức ở thời kỳ đầu của Internet Ngày nay, nó không còn bảo đảm tính an toàn cần thiết trên môi trường Internet toàn cầu vì username và password được gửi qua kênh kết nối điều khiển dưới dạng clear text Điều này làm cho các thông tin đăng nhập có thể bị nghe lén Chuẩn RFC 2228 về các phần mở rộng cho bảo mật FTP đã định ra thêm nhiều tùy chọn chứng thực và
mã hóa phức tạp cho những ai muốn tăng thêm mức độ an toàn vào trong phần mềm FTP của họ
2.4 Quản lý kênh dữ liệu FTP
Kênh điều khiển được tạo ra giữa Server-PI và User-PI sử dụng quá trình thiết lập kết nối và chứng thực được duy trì trong suốt phiên kết nối FTP Các lệnh
và các hồi đáp được trao đổi giữa bộ phận PI (Protocol Interpreter) qua kênh điều khiển, nhưng dữ liệu thì không