Giao thức Tcp

    0

    Cấu trúc gói tin của giao thức Tcp

    Tương tự như Udp, Tcp cũng chỉ vận chuyển các chuỗi byte (mà ứng dụng tạo ra) mà không quan tâm tới ý nghĩa của chúng.

    Dữ liệu của ứng dụng sau khi chuyển qua socket tới tầng giao vận sẽ được giao thức TCP tách thành từng phần. Đối với mỗi phần dữ liệu này, TCP sẽ bổ sung thêm các thông tin điều khiển vào trước phần dữ liệu để tạo thành một đơn vị dữ liệu của tầng giao vận, gọi là TCP segment.

    Phần thông tin điều khiển mà TCP thêm vào trước khối dữ liệu ứng dụng gọi là TCP header. Phần dữ liệu ứng dụng lưu trong TCP segment được gọi là payload. TCP segment sau đó sẽ tiếp tục được chuyển xuống tầng mạng và tiến hành đóng với với giao thức IP để tạo thành một đơn vị dữ liệu của tầng mạng, gọi là IP datagram (hoặc IP package).

    Tại tầng liên kết IP package lại được đóng gói một lần nữa thành Ethernet frame trước khi đưa lên đường truyền vật lý. 

    Cấu trúc của TCP header được trình bày trong sơ đồ dưới đây:

    Ý nghĩa các trường như sau:

    • Source port (16 bit): số cổng của tiến trình gửi. Đối với tiến trình khách, số cổng nguồn sẽ được hệ điều hành cho “mượn” tạm. Đối với tiến trình chủ, số cổng nguồn là cố định và được cấp khi tiến trình gọi lệnh Bind.
    • Destination port (16 bit): số cổng của của tiến trình nhận. Đối với tiến trình khách, số cổng đích chính là số cổng cố định của server đang lắng nghe. Đối với tiến trình chủ, số cổng đích sẽ được biết sau khi nó nhận được yêu cầu kết nối từ tiến trình khách. 
    • Sequence number (32 bit): số thứ tự. Giá trị và ý nghĩa của số thứ tự phụ thuộc vào giá trị của bit SYN.
    • Các trường flag (6 trường, mỗi trường 1 bit):
      • Bit ACK dùng để xác nhận tính chính xác của giá trị trường Acknowledgement.
      • Bit RST, SYN, FIN dùng để thiết lập và hủy bỏ kết nối.
      • Bit PSH chỉ định máy nhận phải chuyển dữ liệu lên tầng trên ngay lập tức.
      • Bit URG chỉ định rằng có vùng dữ liệu được đánh dấu là “urgent” (dữ liệu khẩn). Nếu URG=1, trường Urgent pointer (16 bit) sẽ chứa vị trí của byte cuối cùng của dữ liệu khẩn; TCP phải thông báo về sự tồn tại của dữ liệu khẩn cho máy nhận, đồng thời chuyển cho máy nhận một con trỏ tới cuối của vùng dữ liệu khẩn. Trong thực tế, hai trường PSH và URG không được sử dụng.
    • Checksum (16 bit): sử dụng để kiểm tra lỗi.
    • Window size (16 bit): kích thước cửa sổ dùng trong kiểm soát luồng.
    • Reserved (3 bit): luôn chứa giá trị 000, để dành sử dụng trong tương lai.
    • Data offset (4 bit), còn gọi là Header length: kích thước của TCP header. Kích thước của TCP header có thể thay đổi do sự tồn tại của trường Options. Tuy nhiên, trường Options này thường để trống, và do đó, kích thước của TCP header thường là 20 byte.
    • Acknowledgement number (32 bit): số báo nhận. Trường số thứ tự và số báo nhận được sử dụng để đảm bảo dịch vụ truyền dữ liệu tin cậy.
    • Options (độ dài thay đổi): được sử dụng khi hai máy tham gia truyền thông thỏa thuận về kích thước tối đa của segment (TA: maximum segment size, MSS) hoặc hệ số tỉ lệ của cửa sổ trượt (dùng cho các mạng tốc độ cao).

    Nhìn chung, ngoại trừ số cổng nguồn và cổng đích, chương trình ứng dụng gần như không thể thiết lập được các trường khác của gói tin TCP.

    Quy trình hoạt động của Tcp chia làm 3 giai đoạn: Thiết lập liên kết, Truyền dữ liệu và Đóng liên kết.

    Thiết lập liên kết Tcp

    Khi một tiến trình muốn tiến hành truyền thông với với một tiến trình khác qua mạng sử dụng giao thức TCP, nó phải thông báo cho tầng giao vận để khởi tạo một liên kết TCP. Trong quá trình này, tiến trình khởi tạo liên kết được gọi là tiến trình khách, tiến trình còn lại tiếp nhận liên kết TCP được gọi là tiến trình chủ.

    Quá trình thiết lập liên kết TCP giữa hai tiến trình được thực hiện trong ba bước và thường được gọi là quá trình bắt tay ba bước (three-way handshake).

    Bước 1. Tiến trình khách gửi một TCP segment không chứa dữ liệu tới tiến trình chủ, trong đó, bit SYN = 1. Tiến trình khách sẽ chọn một giá trị ngẫu nhiên cho trường Sequence (để tránh tấn công loại SYN). Segment loại này thường được gọi là SYN segment.

    Bước 2. Khi tiến trình chủ nhận được SYN segment, nó sẽ bố trí bộ nhớ cho TCP buffer và các biến trạng thái cho liên kết TCP. Tiến trình chủ sau đó sẽ gửi một segment trả lời cho tiến trình khách, trong segment này: bit SYN = 1; số báo nhận (ACK number) = Sequence của SYN segment (nhận từ tiến trình khách) + 1; số thứ tự Sequence được lựa chọn ngẫu nhiên. Segment trả lời này thường được gọi là SYNACK segment.  

    Bước 3. Khi nhận được SYNACK segment, tiến trình khách cũng thiết lập bộ nhớ đệm và các biến trạng thái cho liên kết TCP, sau đó gửi lại cho tiến trình chủ một segment, trong đó, trường số báo nhận ACK = số thứ tự Sequence của server + 1, SYN = 0, trường số thứ tự Sequence tăng thêm 1 đơn vị.

    Sau 3 bước này, liên kết TCP giữa hai tiến trình đã được thiết lập.

    Liên kết TCP là loại liên kết song công. Tức là, một khi thiết lập được liên kết giữa tiến trình A và tiến trình B, dữ liệu tầng ứng dụng có thể đồng thời truyền từ A tới B và từ B tới A.

    Liên kết TCP thuộc loại liên kết điểm-điểm giữa duy nhất một tiến trình gửi và một tiến trình nhận. Trong TCP không tồn tại loại truyền thông kiểu quảng bá giữa một tiến trình gửi với nhiều tiến trình nhận.

    Mặc dù quá trình thiết lập liên kết TCP khá phức tạp, thực tế quá trình này được TCP thực hiện tự động khi tiến trình client phát lệnh Connect (và tiến trình server đã phát lệnh Listen). Lệnh Connect của client sẽ bắt đầu bước 1 trong quy trình bắt tay 3 bước. Lệnh Accept của server sẽ khởi động bước 2. Sau khi hoàn thành đủ 3 bước, thuộc tính IsConnected của cả client và server sẽ chuyển sang giá trị true.

    Do server không thể biết trước khi nào client sẽ phát yêu cầu kết nối, lệnh Accept của server phải luôn ở trong trạng thái sẵn sàng để tiếp nhận yêu cầu kết nối. Vì vậy, lệnh Accept thông thường được đặt trong một vòng lặp vô tận.

    Truyền dữ liệu

    Khi đã hình thành liên kết TCP, hai tiến trình tham gia liên kết có thể truyền dữ liệu cho nhau. Khi một tiến trình chuyển một chuỗi byte qua socket tới tầng giao vận, dữ liệu đó sẽ hoàn toàn do TCP trên máy đó quản lý và chịu trách nhiệm.

    Truyền dữ liệu qua liên kết Tcp

    Truyền dữ liệu qua liên kết Tcp: song công, segment, các buffer

    TCP có thể coi như một hệ thống con của hệ điều hành chịu trách nhiệm nhận dữ liệu từ ứng dụng cục bộ cũng như nhận dữ liệu từ máy ở xa.

    Tcp segment

    Đơn vị dữ liệu của Tcp được gọi là segment. Kích thước tối đa của segment (maximum segment size, MSS) được thiết lập tự động bằng cách xác định kích thước tối đa của frame dữ liệu của tầng liên kết. Việc thiết lập MSS như vậy đảm bảo cho TCP segment có thể nằm vừa khít trong một frame với kích thước đủ lớn để có hiệu suất gửi dữ liệu cao nhất.

    Khi TCP gửi đi dữ liệu kích thước lớn (ví dụ, một file video lớn), dữ liệu sẽ được tự động cắt thành từng phần có kích thước bằng MSS (trừ mảnh cuối cùng có thể có kích thước nhỏ hơn). Quá trình này được TCP làm tự động. Chương trình không cần tự động thực hiện cắt dữ liệu. Ở máy đích, các mảnh ghép sẽ được tự động ghép nối lại với nhau. Chương trình ứng dụng luôn nhận được dữ liệu hoàn chỉnh. 

    Ngược lại, các ứng dụng tương tác thường dùng các khối dữ liệu có kích thước nhỏ hơn MSS. Ví dụ, chương trình Telnet thường gửi đi dữ liệu có kích thước đúng 1 byte, do đó kích thước TCP segment dùng với Telnet thường chỉ có 21 byte.

    Tcp buffer

    TCP không lập tức đóng gói dữ liệu và chuyển lên mạng. Thay vào đó, Tcp chuyển dữ liệu tới một bộ nhớ đệm (buffer) được hình thành trong quá trình bắt tay ba bước. Theo thời gian, TCP sẽ lấy dữ liệu (dữ liệu của ứng dụng) từ bộ nhớ đệm, đóng gói thành segment, và chuyển lên đường truyền. Trong khoảng thời gian chờ ở bộ nhớ đệm, ứng dụng có thể gửi thêm dữ liệu và dữ liệu này sẽ tiếp tục được bổ sung vào bộ nhớ đệm. 

    Tương tự, TCP trên máy đích cũng sử dụng một bộ nhớ đệm cục bộ của riêng mình để lưu dữ liệu nhận được cho đến khi nó nhận được đầy đủ tất cả các gói tin theo đúng thứ tự. Sau đó, dữ liệu này mới được chuyển lên cho ứng dụng.

    Do đặc điểm này, các lệnh Send trên máy nguồn và Receive trên máy đích không đồng bộ nhau. Nhiều lệnh Send gửi dữ liệu đi có thể chỉ cần 1 lệnh Receive để nhận dữ liệu về. Đây là điểm khác biệt rất lớn với UDP cần lưu ý.

    Do sử dụng buffer, khi nhìn từ khía cạnh ứng dụng, liên kết và truyền dữ liệu qua Tcp giống như một luồng byte liên tục “chảy” từ buffer của máy nguồn tới buffer của máy đích. Khi tới buffer của máy đích, dữ liệu sẽ chờ được lấy vào chương trình và xử lý. 

    Vì là một dòng byte liên tục, TCP không đảm bảo duy trì “ranh giới” giữa các thông điệp. Việc phân tách nội dung thông điệp tầng ứng dụng thuộc trách nhiệm của chương trình ứng dụng. Đây cũng là một đặc điểm quan trọng cần lưu ý khi lập trình với TCP.

    Khi truyền các file có kích thước lớn, để tối ưu hoạt động của chương trình, người ta thường sử dụng kỹ thuật lập trình luồng dữ liệu. Kỹ thuật lập trình luồng dữ liệu cho phép nối một luồng file với TCP buffer sử dụng một bộ nhớ đệm kích thước nhỏ. Tương tự, ở máy đích, người ta cũng sử dụng kỹ thuật nối luồng giữa TCP buffer và luồng file, thay vì nhận nguyên vẹn một file kích thước lớn từ TCP buffer.

    Việc sử dụng buffer khiến việc lập trình với TCP socket khác biệt rất nhiều so với UDP.

    Acknowledgement

    Mỗi khi Tcp trên máy nguồn gửi đi một segment, nó sẽ chờ nhận được một gói tin phản hồi (ACK) từ máy đối tác thông báo về tình trạng của segment vừa nhận. Chỉ khi có ACK xác nhận đạt yêu cầu, Tcp trên máy nguồn mới tiếp tục gửi đi segment tiếp theo.

    Do những đặc điểm trên, khi tiến trình gửi dữ liệu đi (dưới dạng các thông điệp thuộc tầng ứng dụng), TCP đảm bảo việc chuyển được toàn bộ dữ liệu tới máy đích theo đúng thứ tự, không mất mát và không lỗi.

    Tuy nhiên, toàn bộ quá trình gửi nhận ACK được TCP thực hiện tự động. Chương trình không cần biết về quá trình này, và cũng không thể can thiệp vào quá trình này.

    Đóng liên kết

    Cả hai tiến trình tham gia vào liên kết TCP đều có thể yêu cầu đóng liên kết.

    Khi một trong hai tiến trình muốn kết thúc một liên kết, nó sẽ gửi đi một segment không chứa dữ liệu, trong đó bit FIN = 1.

    Khi tiến trình còn lại nhận được segment này, nó sẽ gửi lại một ACK segment. Tiếp theo tiến trình này sẽ gửi tiếp một segment, trong đó bit FIN = 1.

    Cuối cùng, tiến trình muốn kết thúc liên kết sẽ gửi một ACK segment. Ngay sau đó, bộ nhớ đệm và các biến trạng thái liên quan tới liên kết sẽ được giải phóng và liên kết được ngắt.

    Yêu cầu đóng liên kết sẽ được phát đi khi một tiến trình phát lệnh Close. Toàn bộ quá trình tiếp theo sẽ được TCP thực hiện tự động. Tiến trình không thể can thiệp vào quá trình này. Ngoài ra, lệnh Close còn thực hiện việc giải phóng các tài nguyên mà liên kết này đang chiếm giữ. Do đó, một khi gọi lệnh Close, socket TCP tương ứng sẽ không thể tái sử dụng. Chương trình bắt buộc phải tạo liên kết TCP mới.

    Cần lưu ý, trong lập trình socket TCP còn có thêm lệnh ShutDown. Lệnh này không phát đi yêu cầu ngắt liên kết mà chỉ ngăn không cho thực hiện gửi / nhận dữ liệu qua socket. Thực tế khi phát lệnh Close, socket sẽ tự động gọi tới lệnh ShutDown để ngăn việc gửi thêm dữ liệu, sau đó mới phát đi yêu cầu ngắt liên kết TCP.

    Theo dõi
    Thông báo của
    guest

    0 Thảo luận
    Phản hồi nội tuyến
    Xem tất cả bình luận