2010-03-14 32 views
6

Tôi có một thiết lập máy khách/máy chủ đơn giản. Máy chủ nằm trong C và máy khách đang truy vấn máy chủ là Java.Java thả một nửa gói UDP

Vấn đề của tôi là khi tôi gửi dữ liệu chuyên sâu băng thông qua kết nối, chẳng hạn như khung Video, nó giảm tới một nửa gói. Tôi đảm bảo rằng tôi phân đoạn đúng các gói udp ở phía máy chủ (udp có độ dài tải trọng tối đa là 2^16). Tôi đã xác minh rằng máy chủ đang gửi các gói (printf kết quả của sendto()). Nhưng java dường như không nhận được một nửa dữ liệu.

Hơn nữa, khi tôi chuyển sang TCP, tất cả các khung hình video đều có được nhưng độ trễ bắt đầu tăng lên, thêm vài giây trễ sau một vài giây thời gian chạy.

Có điều gì hiển nhiên mà tôi bị thiếu không? Tôi không thể hình dung ra điều này.

+3

Bạn có chắc chắn đó là "Java" chứ không phải mạng của bạn? Ngoài ra, UDP không đảm bảo về phân phối, đặt hàng hoặc trùng lặp gói - không giống như TCP. – Nate

+3

Thực tế là việc sử dụng kết quả TCP về độ trễ cho tôi biết rằng bạn đang cố gắng đổ vào mạng của bạn nhiều dữ liệu hơn so với dữ liệu có thể mang theo. Vì bạn có các bản ghi từ phía máy chủ gửi các gói tin, bạn sẽ có thể nhận được một ý tưởng chung về số lượng dữ liệu bạn đang gửi mỗi giây. Nó có tương thích với dung lượng mạng của bạn không? – Arkadiy

Trả lời

9

Nhận công cụ mạng như Wireshark để bạn có thể xem điều gì đang xảy ra trên dây.

UDP không thực hiện các lần thử truyền lại, vì vậy nếu gói tin bị loại bỏ ở đâu đó, chương trình sẽ giải quyết vấn đề mất mát. TCP sẽ làm việc chăm chỉ để cung cấp tất cả các gói cho chương trình theo thứ tự, loại bỏ các dups và yêu cầu các gói bị mất một mình. Nếu bạn thấy độ trễ cao, tôi cá là bạn sẽ thấy rất nhiều mất gói tin với TCP, điều này sẽ hiển thị dưới dạng các lần truyền lại từ máy chủ. Nếu bạn không thấy truyền lại TCP, có lẽ máy khách không xử lý dữ liệu đủ nhanh để theo kịp.

+0

Tôi mở wireshark và đổ các gói tin bằng cách sử dụng TCP. Tôi không thấy bất kỳ gói tin nào bị loại bỏ. RTT đến ACK (khoảng thời gian chuyến đi đến ACK) là ~ 40ms. Máy khách Java của tôi sử dụng một chuỗi chuyên dụng để phân tích cú pháp các byte. –

+0

Cảm ơn sự giúp đỡ của bạn, nó đã được giải quyết. Đó là một vấn đề trong thread nhận java (thread đã bị chặn trong một thời gian ngắn không lắng nghe các gói tin). TCP của bạn đã bỏ qua đề xuất theo dõi gói là tốt. –

3

Bất kỳ giao thức ứng dụng dựa trên UDP nào chắc chắn sẽ dễ bị mất gói, sắp xếp lại và (trong một số trường hợp) trùng lặp. Chữ "U" trong UDP có thể là viết tắt của "Unreliable" như trong Unreliable Datagram Protocol. (OK, nó thực sự là viết tắt của "Người dùng" ... nhưng nó chắc chắn là một cách tốt để nhớ đặc điểm của UDP.)

Mất gói UDP thường xảy ra do lưu lượng vượt quá dung lượng đệm của một hoặc nhiều " bước nhảy giữa máy chủ và máy khách. Khi điều này xảy ra, các gói sẽ bị xóa ... và vì bạn đang sử dụng UDP, không có thông báo mức giao thức truyền tải nào đang xảy ra.

Nếu bạn sử dụng UDP trong ứng dụng, ứng dụng cần tính đến bản chất không đáng tin cậy của UDP, triển khai các cơ chế riêng để xử lý các gói bị mất và không theo thứ tự và thực hiện điều khiển luồng riêng. (Một ứng dụng phát tán các gói UDP mà không nghĩ đến hiệu ứng có thể xảy ra trên một mạng đã quá tải là một công dân mạng kém .)

(Trong trường hợp TCP, các gói có thể bị giảm xuống) nhưng TCP đang phát hiện và gửi lại các gói đã bị loại bỏ và cơ chế điều khiển luồng TCP đang khởi động để làm chậm tốc độ truyền dữ liệu. Kết quả thực là "độ trễ".)

EDIT - dựa trên nhận xét của OP , nguyên nhân của vấn đề của anh ta là khách hàng không "lắng nghe" trong một khoảng thời gian, khiến cho các gói tin (có lẽ) bị hệ điều hành của khách hàng giảm xuống. Cách giải quyết này là:

  1. sử dụng một sợi Java chuyên dụng chỉ đọc các gói tin và hàng đợi họ để xử lý, và

  2. tăng kích thước của hàng đợi gói hạt nhân cho các ổ cắm .

Nhưng ngay cả khi bạn thực hiện các biện pháp này, bạn vẫn có thể nhận các gói bị xóa. Ví dụ, nếu máy bị quá tải, ứng dụng có thể không nhận được các lát thời gian thực hiện đủ thường xuyên để đọc và xếp hàng tất cả các gói trước khi hạt nhân phải thả chúng.

CHỈNH SỬA 2 - Có một số tranh luận về việc UDP có dễ bị trùng lặp hay không. Nó chắc chắn đúng là UDP không có phát hiện hoặc ngăn chặn trùng lặp bẩm sinh. Nhưng nó cũng đúng là các gói tin định tuyến IP vải đó là internet không có khả năng tự sao chép các gói tin. Vì vậy, các bản sao, nếu chúng xảy ra, có khả năng xảy ra vì người gửi đã quyết định gửi lại gói UDP.Vì vậy, với tâm trí của tôi trong khi UDP dễ bị các vấn đề với bản sao, nó không gây ra chúng mỗi se ... trừ khi có lỗi trong ngăn xếp giao thức OS hoặc trong vải IP.

+0

Nếu hai gói kết thúc bằng các tuyến đường khác nhau cho khách hàng, bạn có thể không kết thúc với các gói được sắp xếp lại (từ quan điểm của khách hàng) không? –

+0

@Eric Có với UDP, không có TCP. – Fred

+0

Tại sao không trùng lặp? AFAIK, bản sao thực sự là có thể. –

0

Sự cố có thể liên quan đến bộ đệm truyền tải của bạn được điền đầy trong UDPSocket. Chỉ gửi số lượng byte trong một lần được chỉ định bởi UDPSocket.getSendBufferSize(). Sử dụng setSendBufferSize(int size) để tăng giá trị này.

Nếu # Gửi phản() được sử dụng để gửi một DatagramPacket có nghĩa là lớn hơn so với các thiết lập của SO_SNDBUF sau đó nó là thực hiện cụ thể nếu các gói tin được gửi hoặc loại bỏ.

2

Mặc dù UDP hỗ trợ gói lên đến 65535 byte chiều dài (bao gồm header UDP, đó là 8 byte - nhưng xem ghi chú 1), vận tải cơ bản giữa bạn và điểm đến không hỗ trợ gói IP mà dài . Ví dụ, các khung Ethernet có kích thước tối đa 1500 byte - có tính đến chi phí cho các tiêu đề IP và UDP, có nghĩa là bất kỳ gói UDP nào có chiều dài tải dữ liệu lớn hơn khoảng 1450 có thể bị phân mảnh thành nhiều gói dữ liệu IP.

Gói UDP kích thước tối đa sẽ được chia thành ít nhất 45 gói dữ liệu IP riêng biệt - và nếu bất kỳ của những đoạn đó bị mất, toàn bộ gói UDP bị mất. Nếu tỷ lệ mất gói tin cơ bản của bạn là 1%, ứng dụng của bạn sẽ thấy tỷ lệ mất khoảng 36%!

Nếu bạn muốn thấy ít gói bị mất hơn, đừng gửi gói lớn - giới hạn dữ liệu của bạn trong mỗi gói đến khoảng 1400 byte (hoặc thậm chí thực hiện khám phá Path MTU của riêng bạn để tìm ra kích thước tối đa gửi mà không bị phân mảnh).


  1. Tất nhiên, UDP cũng tuỳ thuộc vào những hạn chế của IP và IP datagram có kích thước tối đa 65.535, trong đó có tiêu đề IP. Header dãy IP có kích thước từ 20 đến 60 byte, vì vậy số tiền tối đa của dữ liệu ứng dụng vận chuyển trong một gói tin UDP có thể là càng thấp càng 65467.
+0

Một số điểm không chính xác ở đó, hãy xem câu trả lời của tôi. – EJP

+0

Lời khuyên thiết thực tốt - ngay cả khi có một số cuộc tranh luận về kích thước của tiêu đề UDP (tám byte, từ bộ nhớ). Đối với hầu hết các ứng dụng truyền trực tuyến, việc giữ kích thước gói dữ liệu UDP đủ nhỏ để vừa với khung ethernet có một số ưu điểm: giảm thiểu mất dữ liệu khi khung bị mất; giảm độ trễ vì không cần phải đợi toàn bộ gói dữ liệu; và - đối với một số ứng dụng - có thể giảm tải xử lý bằng cách tắt tính năng kiểm tra UDP cho luồng và dựa vào phát hiện lỗi ethernet để loại bỏ các khung/datagram bị lỗi. MPEG thường được gửi dưới dạng khung hình 7 x 188 byte TS trên mỗi gói dữ liệu UDP. – Dipstick

0

IP hỗ trợ gói lên đến 65535 byte trong đó có một tiêu đề gói tin IP byte. UDP hỗ trợ datagrams tối đa 65507 byte, cộng với tiêu đề IP 20 byte và tiêu đề UDP byte UDP. Tuy nhiên MTU mạng là giới hạn thực tế, và đừng quên rằng không chỉ bao gồm 28 byte mà còn là tiêu đề khung Ethernet. Các thực giới hạn thực tế cho UDP không bị phân mảnh là MTU tối thiểu 576 byte ít hơn tất cả các chi phí.

+2

Ethernet có khung, không phải gói. Ethernet MTU là 1500 byte ** trọng tải **, xác định kích thước tối đa của một đoạn IP; nó không bao gồm tiêu đề khung và đuôi. 576 là MTU tối thiểu một nút phải hỗ trợ để truyền các đoạn IP, nó không phải là giới hạn thực tế thực tế cho UDP không bị phân mảnh. Giới hạn này phải được xác định thông qua phát hiện MTU đường dẫn. Ngoài ra, nó có thể gửi datagrams lớn hơn MTU mà không làm cho nó không thực tế, cho đến khi datagrams hoặc mất gói quá lớn. – Juliano

+0

Cảm ơn, những sửa đổi này thậm chí còn tốt hơn. – EJP

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