Các gói TCP và UDP có thể được chia thành từng mảnh không?


41

Các gói TCP có thể đến máy thu theo từng mảnh không?

Ví dụ: nếu tôi gửi 20 byte bằng giao thức TCP, tôi có thể chắc chắn 100% rằng tôi sẽ nhận được chính xác 20 byte cùng một lúc, không phải 10 byte sau đó thêm 10 byte nữa không?

Và câu hỏi tương tự cho giao thức UDP.
Tôi biết rằng UDP không đáng tin cậy và các gói không thể đến được hoặc đến theo thứ tự khác nhau, nhưng còn một gói thì sao? Nếu nó đến, tôi có thể chắc chắn rằng đó là một gói hoàn chỉnh, không phải là một mảnh?


7
Một điểm cần làm rõ: Nó được gọi là phân đoạn TCP và datagram UDP. Chúng không phải là gói. TCP = Segment, UDP = Datagram, IP = Packet, Ethernet = Frame, Tại tất cả các lớp khác (AFAIK) chúng chỉ được gọi là PDU (Đơn vị dữ liệu giao thức).
joeqwerty

Câu trả lời:


33

các gói TCP có thể đến máy thu theo từng mảnh không?

Đúng. IP hỗ trợ phân mảnh, mặc dù TCP thường cố gắng xác định MTU đường dẫn và giữ các gói của nó nhỏ hơn so với lý do hiệu suất. Sự phân mảnh làm tăng tỷ lệ mất datagram một cách thảm khốc. Nếu một đường dẫn có tỷ lệ mất gói 10%, việc phân chia một datagram thành hai gói làm cho tỷ lệ mất datagram gần như 20%. (Nếu một trong hai gói bị mất, datagram sẽ bị mất.)

Bạn không phải lo lắng về điều này mặc dù và lớp TCP cũng không. Lớp IP tập hợp lại các gói thành toàn bộ datagram.

Ví dụ: nếu tôi gửi 20 byte bằng giao thức TCP, tôi có thể chắc chắn 100% rằng tôi sẽ nhận được chính xác 20 byte cùng một lúc, không phải 10 byte sau đó thêm 10 byte nữa không?

Không, nhưng điều đó không liên quan gì đến các gói. Về cơ bản, TCP là một giao thức luồng byte không bảo toàn ranh giới thông điệp ứng dụng.

Và câu hỏi tương tự cho giao thức UDP. Tôi biết rằng UDP không đáng tin cậy và các gói không thể đến được hoặc đến theo thứ tự khác nhau,

Điều này cũng đúng với TCP. Các gói là các gói. Sự khác biệt là TCP đã thử lại và sắp xếp lại được tích hợp vào giao thức trong khi UDP thì không.

Nhưng còn 1 gói thì sao? Nếu nó đến, tôi có thể chắc chắn rằng đó là một gói hoàn chỉnh, không phải là một mảnh?

Không, nhưng đó không phải là vấn đề của bạn. Giao thức UDP xử lý việc cài đặt lại datagram. Đó là một phần công việc của nó. . sẽ thấy dữ liệu đầy đủ.


10
Có thể đáng làm rõ bit cuối cùng cho người đọc mới làm quen: bạn sẽ thấy dữ liệu đầy đủ cho datagram đang đề cập . Nếu bất kỳ một trong các gói phân tách bị mất, datagram sẽ bị mất và lớp UDP sẽ không bao giờ biết về nó. Miễn là tất cả các gói trong datagram được nhận, chúng sẽ được lắp ráp ở lớp IP và sau đó được chuyển lên lớp UDP. Điều này không loại trừ khả năng thiếu "khối" trong kho dữ liệu. Không phải là một giáo viên, nhưng khi tôi học thứ này, tôi đã không tìm ra sự khác biệt giữa mất IP và mất UDP cho đến khi thứ 2 hoặc thứ 3 đi qua sách giáo khoa.
Justin

20

Bạn không thể chắc chắn rằng họ thực sự đến một lúc. Các lớp liên kết dữ liệu bên dưới TCP / UDP có thể chia gói của bạn lên nếu chúng muốn. Đặc biệt nếu bạn gửi dữ liệu qua internet hoặc bất kỳ mạng nào ngoài tầm kiểm soát của bạn, thật khó để dự đoán điều đó.

Nhưng không có vấn đề nếu dữ liệu đến trong một gói hoặc nhiều gói tại máy thu. Hệ điều hành nên trừu tượng hóa việc ghép các gói này, vì vậy đối với ứng dụng của bạn, nó vẫn giống như mọi thứ xuất hiện cùng một lúc. Vì vậy, trừ khi bạn là một hacker hạt nhân, trong hầu hết các trường hợp, bạn không cần phải lo lắng nếu dữ liệu này được truyền trong một hoặc nhiều gói.

Đối với UDP, HĐH cũng sẽ thực hiện một số trừu tượng, do đó, ứng dụng nhận dữ liệu không cần phải biết có bao nhiêu gói dữ liệu được truyền đi. Nhưng sự khác biệt đối với TCP là không có gì đảm bảo dữ liệu thực sự đến. Cũng có thể dữ liệu được chia thành nhiều gói và một số trong số chúng đến và một số thì không. Đối với ứng dụng nhận, dù sao nó cũng giống như một luồng dữ liệu, bất kể nó đã hoàn thành hay chưa.


Trình điều khiển card mạng có quan tâm đến việc tập hợp lại các gói không phải kernel không?
bluehallu

2
@Hallucynogenyc: Trừ khi mọi thứ thay đổi, giao thức Internet được thiết kế để cho phép các gói trên 576 byte được phân chia tại bất kỳ điểm nào trên hành trình của chúng, nhưng không mong đợi gì ngoài người nhận cuối cùng kết hợp lại chúng. Tôi nghĩ rằng ý tưởng là việc sử dụng các gói lớn hơn trong hầu hết các trường hợp là một nỗ lực để giảm chi phí; một khi một gói đã bị tách ra tại một thời điểm nào đó trên hành trình của nó, thì chi phí đã được phát sinh để kết hợp lại trước khi người nhận cuối cùng không có khả năng giúp đỡ bất cứ điều gì và có thể bị tổn thương nếu phải chia lại.
supercat

Tôi tin rằng trong khi bất kỳ gói nào có trên 576 byte có thể bị phân tách, thì các gói dưới kích thước đó có thể không được phân chia; các hệ thống nhúng không thể xử lý các gói phân tách nên tránh yêu cầu bất cứ thứ gì lớn hơn thế.
supercat

1
@ mauro.stettler: Tôi đã viết một ngăn xếp TCP trên "kim loại trần" (viết mã để nói chuyện trực tiếp với một số chip giao diện mạng). Đối với phần cứng nói chuyện với một liên kết có giới hạn 576 byte để phân chia các gói dài hơn thì đơn giản. Reassembling gói là nhiều hơn phức tạp, đặc biệt là kể từ khi người ta có thể nhận được mảnh nhiều gói khác nhau trước khi bất kỳ trong số họ được nhận đầy đủ.
supercat

Có một số hy vọng rằng nó sẽ không bị chia cho các tải trọng nhỏ (khoảng 10 hoặc 20 byte là ổn), bởi vì có một "kích thước tối đa được đảm bảo" cần thiết cho mỗi hop cho các gói IP trên ipv4: ít nhất là 68 byte (bao gồm Tiêu đề IP và không tính các tiêu đề cấp thấp hơn). xem bảng 1 trong en.wikipedia.org/wiki/Maximum_transmission_unit . Khác với 576 byte có kích thước tối thiểu được yêu cầu từ HOSTS (nghĩa là nguồn gốc hoặc kết thúc truyền, không phải tất cả các bước nhảy trung gian). Và cẩn thận: tải trọng vẫn thấp hơn (vì các tiêu đề của mỗi lớp chiếm một khoảng trống).
Olivier Dulac

14

Ví dụ. Các khối ký tự liền kề tương ứng với các lệnh gọi ():

TCP:

Send: AA BBBB CCC DDDDDD E         Recv: A ABB B BCC CDDD DDDE

Tất cả dữ liệu gửi được nhận theo thứ tự, nhưng không nhất thiết phải trong cùng một khối.

UDP:

Send: AA BBBB CCC DDDDDD E         Recv: CCC AA E

Dữ liệu không nhất thiết phải theo cùng một thứ tự và hoàn toàn không nhất thiết phải nhận, nhưng các thông điệp được lưu giữ toàn bộ.


5

Ví dụ: nếu tôi gửi 20 byte bằng giao thức TCP, tôi có thể chắc chắn 100% rằng tôi sẽ nhận được chính xác 20 byte cùng một lúc, không phải 10 byte sau đó thêm 10 byte nữa không?

Không, TCP là một giao thức truyền phát, nó giữ dữ liệu theo thứ tự nhưng nó không nhóm nó theo tin nhắn. Mặt khác, UDP được định hướng theo thông điệp, nhưng không đáng tin cậy. SCTP có thế giới tốt nhất nhưng không thể sử dụng được vì NAT phá vỡ Internet.


1

Có một số đảm bảo rằng nếu bạn gửi 20 byte ở đầu luồng TCP, nó sẽ không đến dưới dạng hai mảnh 10 byte. Điều này là do ngăn xếp TCP sẽ không gửi các phân đoạn nhỏ như vậy: có kích thước MTU tối thiểu. Tuy nhiên, nếu việc gửi ở bất cứ đâu ở giữa luồng, tất cả các cược sẽ bị tắt. Có thể là ngăn xếp giao thức của bạn mất 10 byte dữ liệu để điền vào một phân đoạn và gửi nó ra, và sau đó mười byte tiếp theo chuyển sang phân đoạn khác.

Ngăn xếp giao thức của bạn chia dữ liệu thành các khối và đặt chúng vào hàng đợi. Các kích thước khối được dựa trên đường dẫn MTU. Nếu bạn thực hiện thao tác gửi và vẫn còn dữ liệu xếp hàng chờ xử lý, ngăn xếp giao thức thường sẽ nhìn trộm phân đoạn nằm ở đuôi hàng đợi và xem liệu có chỗ trong phân đoạn đó để thêm dữ liệu không. Căn phòng có thể nhỏ như một byte, do đó, ngay cả một lần gửi hai byte cũng có thể được chia thành hai.

Mặt khác, phân đoạn dữ liệu có nghĩa là có thể có một phần đọc. Một hoạt động nhận có khả năng có thể thức dậy và có được dữ liệu khi có ít nhất một phân đoạn đến. Trong API ổ cắm được triển khai rộng rãi, một cuộc gọi nhận có thể yêu cầu 20 byte, nhưng nó có thể trả về bằng 10. Tất nhiên, một lớp đệm có thể được xây dựng trên đó sẽ chặn cho đến khi nhận được 20 byte hoặc ngắt kết nối. Trong thế giới POSIX, API đó có thể là luồng I / O tiêu chuẩn: bạn có thể fdopenmô tả ổ cắm để có được FILE *luồng và bạn có thể sử dụng freadnó để điền vào bộ đệm sao cho yêu cầu đầy đủ được đáp ứng với nhiều readcuộc gọi như vậy .

Các datagram UDP đóng khung dữ liệu. Mỗi cuộc gọi gửi sẽ tạo ra một datagram (nhưng xem bên dưới về nút chai). Phía bên kia nhận được một datagram đầy đủ (và, trong API socket, nó phải chỉ định một bộ đệm đủ lớn để chứa nó, nếu không thì datagram sẽ bị cắt ngắn). Các datagram lớn bị phân mảnh bởi phân mảnh IP và được lắp ráp lại trong suốt cho các ứng dụng. Nếu bất kỳ đoạn nào bị thiếu, toàn bộ datagram sẽ bị mất; không có cách nào để đọc một phần dữ liệu trong tình huống đó.

Có các phần mở rộng cho giao diện cho phép nhiều thao tác chỉ định một datagram duy nhất. Trong Linux, một ổ cắm có thể bị "đóng nút" (không thể gửi). Trong khi nó được đóng nút, dữ liệu bằng văn bản được tập hợp thành một đơn vị. Sau đó, khi ổ cắm được "mở khóa", một datagram duy nhất có thể được gửi.


Điều này là sai: nếu một người gửi một paquet với tải trọng 10 hoặc 20 byte, điều này sẽ tạo ra 1 paquet và (như tôi đã nói ở trên), nếu sử dụng ipv4, thì ngay cả khi thêm tất cả các tiêu đề của các lớp giao thức khác, sẽ phù hợp trong vòng 68 byte, do đó đảm bảo rằng nó đi qua tất cả các bước trong 1 gói. Tcp stack sẽ không (như được gợi ý trong đoạn 1 của bạn) "hãy đợi cho đến khi mtu được lấp đầy (nghĩa là thêm một vài gói để tạo một gói có kích thước phù hợp)" để gửi một gói! ... Hành vi này sẽ phá vỡ nhiều thứ ( ngay cả khi những "mảnh vỡ" đó được gửi từ & đến cùng một cặp máy chủ)
Olivier Dulac

@OlivierDulac: Điều đó không chính xác. TCP thường tạo ra các gói theo nhu cầu, cố gắng tối ưu hóa việc sử dụng mạng, do đó 20 byte có thể kết thúc thành hai gói khác nhau như Kaz giải thích. Điều này có thể được kiểm soát bằng tùy chọn ổ cắm TCP_NODELAY , vô hiệu hóa thuật toán Nagles gửi byte đến các gói, nếu ứng dụng của bạn cần kết nối mạng TCP nhanh hơn. Ngoài ra, 68 byte hoàn toàn không phải là tiêu chuẩn thực tế cho độ dài gói: 1500 byte là giá trị mặc định thông thường hơn (giá trị này thực sự khác nhau giữa các mạng).
jjmontes
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.