2009-10-07 27 views
9

Khi tôi gửi()/write() một tin nhắn qua luồng tcp, làm thế nào tôi có thể tìm hiểu xem các byte đó có được gửi thành công không?Tìm hiểu xem tin nhắn trên tcp đã được gửi chưa

Người nhận xác nhận nhận byte qua tcp, do đó, người gửi tcp stack nên biết. Nhưng khi tôi gửi() một số byte, gửi() ngay lập tức trả về, ngay cả khi gói không thể được gửi, tôi đã thử nghiệm trên linux 2.6.30 sử dụng strace trên netcat, kéo cáp mạng của tôi ra trước đó gửi một số byte.

Tôi chỉ đang phát triển một ứng dụng rất quan trọng để biết liệu thư có được gửi hay không, nhưng thực hiện các tính năng tcp ("ack for message # 123") cảm thấy khó xử, phải có cách tốt hơn.

Trả lời

19

TCP gửi không biết khi dữ liệu được xác nhận bởi đầu kia, nhưng lý do duy nhất nó thực hiện điều này là nó biết khi nào nó có thể loại bỏ dữ liệu (vì ai đó hiện đang chịu trách nhiệm đưa nó vào ứng dụng ở phía bên kia).

Nó thường không cung cấp thông tin này cho ứng dụng gửi, bởi vì (mặc dù xuất hiện) nó sẽ không thực sự có nghĩa là nhiều cho ứng dụng gửi. Sự thừa nhận không có nghĩa là ứng dụng nhận đã có dữ liệu và thực hiện một cái gì đó hợp lý với nó - tất cả điều đó có nghĩa là TCP gửi không còn phải lo lắng về nó nữa. Dữ liệu vẫn có thể đang chuyển tiếp - trong một máy chủ proxy trung gian, ví dụ hoặc trong ngăn xếp TCP nhận.

"Dữ liệu đã nhận thành công" thực sự là khái niệm cấp ứng dụng - ý nghĩa của nó thay đổi tùy thuộc vào ứng dụng (ví dụ: đối với nhiều ứng dụng, chỉ cần xem xét dữ liệu "đã nhận" khi nó đã được đồng bộ hóa với đĩa trên mặt nhận). Vì vậy, điều đó có nghĩa là bạn phải tự mình thực hiện, bởi vì với tư cách là nhà phát triển ứng dụng, bạn thực sự là người duy nhất ở vị trí biết cách làm điều đó một cách hợp lý cho ứng dụng của bạn.

8

Có người nhận gửi lại một ack là cách tốt nhất, ngay cả khi nó "cảm thấy khó xử". Hãy nhớ rằng IP có thể phá vỡ dữ liệu của bạn thành nhiều gói và tập hợp lại chúng, và điều này có thể được thực hiện nhiều lần cùng với quá trình truyền nếu các bộ định tuyến khác nhau có MTUs khác nhau và do đó khái niệm "gói" và TCP có thể không đồng ý. Bạn có thể gửi "gói" của mình, cho dù đó là một chuỗi, một đối tượng được tuần tự hóa, hoặc dữ liệu nhị phân, và yêu cầu người nhận thực hiện bất kỳ thao tác kiểm tra nào cần thực hiện để làm cho nó ở đó và gửi lại một xác nhận.

+0

Sự thật là đúng, nhưng tôi không thích cách nói. TCP là một giao thức đáng tin cậy, bạn ** sẽ ** nghe về nó nếu việc truyền tải thất bại. Thực tế là bạn không cần phải yêu cầu một ACK từ phía xa là một tính năng, không phải là một lỗi. Cách "tốt nhất" để giải quyết vấn đề này là ** bỏ qua ** vấn đề ở cấp độ các cuộc gọi và byte hệ thống. Nếu bạn cần một kết quả trở lại, làm điều đó ở cấp độ của giao thức, không phải là ổ cắm. –

6

Giao thức TCP cố gắng hết sức để đảm bảo dữ liệu của bạn đến. Nếu có sự cố mạng, nó sẽ truyền lại dữ liệu một vài lần. Điều đó có nghĩa là bất cứ điều gì bạn gửi được đệm và không có cách kịp thời để đảm bảo rằng nó đã đến (sẽ có một thời gian chờ 2 phút sau đó nếu mạng là xuống).

Nếu bạn cần phản hồi nhanh, hãy sử dụng giao thức UDP. Nó không sử dụng bất kỳ chi phí TCP nào nhưng bạn phải tự xử lý tất cả các vấn đề.

+0

Vâng, theo thiết kế, nó đáng tin cậy và được đặt hàng – RichardOD

3

Lớp ứng dụng không kiểm soát được thông báo ở các tầng thấp hơn (chẳng hạn như tầng Giao vận) trừ khi chúng được cung cấp cụ thể - đây là theo thiết kế. Nếu bạn muốn biết TCP đang làm gì trên một mức gói tin, bạn cần phải tìm hiểu ở lớp mà TCP hoạt động tại; điều này có nghĩa là xử lý các tiêu đề TCP và dữ liệu ACK.

Tuy nhiên, bất kỳ giao thức nào bạn sử dụng để thực hiện tải trọng của mình đều có thể được sử dụng để chuyển các tin nhắn qua lại bằng cách tải trọng đó. Vì vậy, nếu bạn cảm thấy khó xử khi sử dụng các bit của một tiêu đề TCP để làm điều này, chỉ cần thiết lập nó trong ứng dụng của bạn. Ví dụ:

A: Send 450 Bytes 
B: Recv 450 Bytes 
B: Send 'I got 450 Bytes' 
A: Recv 'B got the full message' 
A: Continue 
1

Điều này nghe có vẻ như SCTP có thể là điều cần xem; Tôi nghĩ rằng nó sẽ hỗ trợ những gì bạn muốn. Cách thay thế có vẻ là chuyển sang UDP và nếu bạn đang chuyển đổi giao thức thì

3

Thậm chí nếu nó có được như xa như lớp TCP, không có đảm bảo rằng nó không nằm trong bộ đệm của ứng dụng, sau đó ứng dụng bị rơi trước khi nó có thể xử lý nó. Sử dụng xác nhận, đó là những gì mọi thứ khác làm (ví dụ: SMTP)

Các vấn đề liên quan