Độ tin cậy xác nhận bằng UDP


16

Tôi có một câu hỏi về UDP. Đối với bối cảnh, tôi đang làm việc trên một trò chơi hành động thời gian thực.

Tôi đã đọc khá nhiều về sự khác biệt giữa UDP và TCP và tôi cảm thấy tôi hiểu chúng khá rõ, nhưng có một điều chưa bao giờ cảm thấy chính xác, đó là độ tin cậy và đặc biệt là sự thừa nhận . Tôi hiểu rằng UDP không cung cấp độ tin cậy theo mặc định (nghĩa là các gói có thể bị mất hoặc không theo thứ tự). Khi cần một số độ tin cậy, giải pháp tôi đã thấy (có ý nghĩa về mặt khái niệm) là sử dụng các xác nhận (tức là máy chủ gửi một gói đến máy khách và khi máy khách nhận được thông báo đó, nó sẽ gửi lại một xác nhận cho máy chủ) .

Điều gì xảy ra khi xác nhận bị bỏ?

Trong ví dụ trên (một máy chủ gửi gói đến một máy khách), máy chủ xử lý mất gói tiềm năng bằng cách gửi lại gói mỗi khung cho đến khi nhận được xác nhận cho các gói đó. Bạn vẫn có thể gặp phải các vấn đề về băng thông hoặc tin nhắn không theo thứ tự, nhưng hoàn toàn từ góc độ mất gói, máy chủ được bảo vệ.

Tuy nhiên, nếu khách hàng gửi một xác nhận không bao giờ đến, máy chủ sẽ không có lựa chọn nào khác ngoài việc dừng gửi tin nhắn đó, điều này có thể phá vỡ trò chơi nếu thông tin chứa trong gói đó là bắt buộc. Bạn có thể thực hiện một cách tiếp cận tương tự với máy chủ (nghĩa là tiếp tục gửi xác nhận cho đến khi bạn nhận được ack cho ack?), Nhưng cách tiếp cận đó sẽ khiến bạn lặp đi lặp lại mãi mãi (vì bạn cần ack cho ack cho ack và như thế).

Tôi cảm thấy logic cơ bản của tôi là chính xác ở đây, điều này cho tôi hai lựa chọn.

  1. Gửi một gói xác nhận duy nhất và hy vọng điều tốt nhất.
  2. Gửi một số gói xác nhận (có thể 3-4) và hy vọng điều tốt nhất, cho rằng không phải tất cả chúng sẽ bị loại bỏ.

Có một câu trả lời cho vấn đề này? Tôi có hiểu nhầm về cơ bản một cái gì đó? Có một số đảm bảo về việc sử dụng UDP mà tôi không biết? Tôi cảm thấy do dự để tiến về phía trước với quá nhiều mã mạng cho đến khi tôi cảm thấy thoải mái rằng logic của tôi là âm thanh.


11
Có lẽ bạn đang thiếu một ý tưởng về "thời gian chờ" và "thử lại".
Kromster nói hỗ trợ Monica

Tôi có thể, chắc chắn. Bạn đang cho rằng logic của tôi là chính xác và, không có vẻ quá tiêu cực, nhưng trong khi lập trình mạng, tôi có thể cho rằng không có sự đảm bảo nào về hầu như bất kỳ mẩu thông tin nào được nối mạng? Trong quá trình chơi trò chơi thời gian thực, đó là một tấn thông tin có khả năng bị bỏ đi, điều này rất tốt, nhưng tôi chỉ muốn chắc chắn rằng tôi hiểu vấn đề.
Grimelios

10
Không đảm bảo nào cả. Đúng. Đừng bao giờ bao gồm "hy vọng" trong thuật toán của bạn. Họ phải xử lý bất kỳ kết hợp không may mắn. PS Chúng tôi chỉ đơn giản chuyển sang TCP trong RTS của chúng tôi, nơi eberything được chăm sóc, vì chúng tôi cần giao tiếp đáng tin cậy (để mô phỏng bước khóa).
Kromster nói hỗ trợ Monica

5
Sử dụng TCP khi cần độ tin cậy, sử dụng UDP khi không thành vấn đề. Ví dụ: tọa độ của người chơi được gửi trong trò chơi của tôi thông qua UDP. Tôi sử dụng phép nội suy & làm mịn để làm mịn mọi gói bị thiếu. hoạt động như một lá bùa. những thứ thực sự cần phải đáng tin cậy nhưng có thể chậm hơn một chút được gửi qua TCP. Nếu bạn có trạng thái ở trạng thái mới hơn làm mất hiệu lực trạng thái cũ, UDP là một lựa chọn tốt vì điều đó không thành vấn đề khi một cái gì đó ở giữa bị bỏ 8e.g. vị trí người chơi).
Polygnome

Đây không phải là câu trả lời trực tiếp cho câu hỏi của bạn, nhưng tôi thực sự khuyên bạn chỉ nên yêu cầu xác nhận trong trò chơi thời gian thực khi chúng thực sự cần thiết (ví dụ: về kết nối ban đầu). Thật đơn giản (và mạnh mẽ) khi thiết kế cả máy khách và máy chủ để chúng "làm việc với những gì chúng có" cho đến khi chúng nhận được một gói mới trong một hệ thống không trạng thái nếu bạn có thể. Quake 3 đã làm điều này cực kỳ tốt với một hệ thống dựa trên ảnh chụp nhanh . Ngoài ra các thư viện như Enet chỉ có thể gửi một số gói tin đáng tin cậy, cho những trường hợp khi bạn thực sự cần nó
jrh

Câu trả lời:


32

Đây là một dạng của Vấn đề Hai Tướng và bạn nói đúng - không có số lần thử lại nào đủ để đảm bảo hoàn thành việc nhận.

Trong thực tế trong các trò chơi, thường có một khoảng thời gian mà thông tin không thực sự quan trọng mặc dù về mặt kỹ thuật nó đến một cách đáng tin cậy. Giống như phát hiện ra bạn đã có một headshot hoàn hảo xếp hàng 2 giây trước - bây giờ đã quá muộn để người chơi sử dụng thông tin đó.

Nếu mất gói tin của bạn quá cao đến nỗi bạn không thể thường xuyên nhận được thông tin cần thiết thông qua bên trong một cửa sổ phản ứng chặt chẽ, thì đối với một trò chơi thời gian thực, bạn có thể nên đá người chơi và cố gắng tìm một kết quả tốt hơn cho họ ở nơi khác, thay vì tiếp tục cố gắng gửi gói để mô phỏng một kết nối đáng tin cậy.

Bởi vì điều này, một số hệ thống sao chép trò chơi bỏ qua xác nhận & thử lại hoàn toàn và chọn chỉ spam bản cập nhật mới nhất có thể. Nếu một người bị rơi hoặc đến muộn, quá tệ, hãy bỏ qua nó, nhặt cái tiếp theo và tiếp tục, dựa vào các hệ thống dự đoán và nội suy để làm phẳng khoảng cách và giảm thiểu các trục trặc có thể nhìn thấy cho người chơi.

Tôi đột nhiên muốn bắt đầu gọi đây là "Bản sao Simba" để biết cách nó coi nhẹ các vấn đề trong quá khứ và cố gắng sống trong thời điểm hiện tại. ;)

Rafiki đặt ra một số vô lý quảng cáo trên triết lý cuộc sống đó

Một giải pháp lai là chạy đua trước khi gửi bản cập nhật mới VÀ (vì các bản cập nhật trạng thái trò chơi thường có thể khá nhỏ / có thể nén được ) cũng đóng gói trong bản cập nhật cuối cùng và có thể là bản trước đó ... Vì vậy, trong trường hợp khách hàng bỏ lỡ chúng , bạn không phải đợi toàn bộ thời gian chuyến đi để tìm hiểu và khắc phục nó. Hầu hết thời gian khách hàng đã thấy điều này, do đó, có dữ liệu dư thừa theo cách này, nhưng độ trễ để sửa tin nhắn bị bỏ lỡ thấp hơn. Các bản cập nhật của khách hàng có thể bao gồm số chỉ mục của bản cập nhật liên tiếp gần đây nhất mà họ đã thấy, do đó bạn có thể bảo thủ tối thiểu với số lượng cập nhật cũ mà bạn đưa vào gói cập nhật tiếp theo.

Bạn cũng có thể triển khai hệ thống hai lớp như một loại kết hợp khác, trong đó trạng thái tồn tại ngắn được sao chép theo cách bắn nhanh không đáng tin cậy và trạng thái dài hạn được đồng bộ hóa đáng tin cậy, sử dụng TCP hoặc triển khai độ tin cậy của chính bạn với độ thử lại cao đếm. Điều này trở nên phức tạp hơn để quản lý, bởi vì bạn có hai hệ thống nhắn tin để duy trì và hai ảnh chụp nhanh có thể không đồng bộ với nhau, thêm một lớp vỏ hoàn toàn mới.


1
+1, được viết tốt. Tôi chỉ nhấn mạnh rằng điều này có liên quan nhiều hơn đến các game hành động / thời gian thực. Các trò chơi TBS và RTS (và một số sự kiện của trò chơi hành động) có một cái nhìn khác về "chân trời thời gian mà thông tin không thực sự quan trọng".
Kromster nói hỗ trợ Monica

3
Vâng, đối với một trò chơi theo lượt, tôi tưởng tượng một người sẽ sử dụng TCP thay vì cố gắng cuộn lớp tin cậy của chính mình lên trên UDP. ) mạng lưới an toàn để xử lý hồi tố các sự kiện bị bỏ lỡ quan trọng như chi tiêu tài nguyên.
DMGregory

Điều đó cực kỳ hữu ích và xác thực mối quan tâm ban đầu của tôi. Cảm ơn rât nhiều.
Grimelios

2
Nó cũng có thể hữu ích để đề cập đến sửa lỗi chuyển tiếp. Thiết kế giao thức của bạn sao cho người nhận có thể độc lập tìm ra một gói bị bỏ khi nhận gói tiếp theo, thêm một số dữ liệu bổ sung để làm mịn nội suy yêu cầu. Điều này có thể hữu ích vì thường các gói UDP không đầy đủ và bạn chỉ cần gửi các gói nhỏ hơn thường xuyên hơn để giảm độ trễ. Thêm một số byte bổ sung sẽ không ảnh hưởng đến độ trễ và băng thông không phải là vấn đề trong những trường hợp này.
MSalters

@MSalters Tôi muốn nói rằng điều đó đáng để xây dựng trong câu trả lời của riêng mình, nếu bạn đồng ý. Tôi muốn nâng cao điều đó. :)
DMGregory

9

Cách tiếp cận TCP sử dụng là người gửi sẽ tiếp tục gửi lại gói cho đến khi nhận được xác nhận. Người nhận sẽ bỏ qua các gói trùng lặp, nhưng vẫn gửi xác nhận cho họ. Người gửi sẽ bỏ qua các xác nhận trùng lặp.

Nếu một gói bị mất, người gửi gửi lại nó, như bạn đã biết.
Nếu một xác nhận bị mất, người gửi gửi lại gói ban đầu, khiến cho người nhận gửi lại xác nhận.

Nếu một xác nhận không được nhận trong một thời gian nhất định (có thể là 60 giây hoặc 20 lần thử lại) thì người chơi được coi là bị ngắt kết nối khỏi trò chơi. Bạn phải thực hiện một số loại quy tắc hết thời gian, hoặc nếu không, người chơi rút cáp mạng của họ sẽ liên kết tài nguyên trên máy chủ của bạn mãi mãi.


Một tính năng thiết yếu của TCP là người gửi không cần quan tâm đến việc có bất kỳ gói tin cụ thể nào được thừa nhận hay không, nhưng chủ yếu cần quan tâm đến "vạch nước cao" và thời gian các gói tin nổi bật mà không có dấu hiệu nước cao di chuyển.
supercat

1
@supercat Tôi không nói đó là điều cần thiết; giống như một sự tối ưu hóa
dùng253751

Về điều trong ngoặc đơn (gửi ACK cho các gói bạn đã có), tôi nghĩ bạn thực sự nên nhấn mạnh nó thay vì ngoặc đơn. Nó dường như bị thiếu trong sự hiểu biết của OP (hoặc ít nhất là mô tả của nó).
Phục hồi Monica

@Angew thực hiện ngay.
dùng253751

6

Nếu bạn muốn phát minh lại TCP, trước tiên hãy xem xét TCP , giải quyết vấn đề chính xác mà bạn mô tả (một phần của giải pháp là sử dụng các giá trị do người dùng xác định để thử lại và hết thời gian chờ).

Các giải pháp sử dụng 2 kênh, kênh TCP (để liên lạc đáng tin cậy) cũng như kênh UDP (cho giao tiếp có độ trễ thấp) không phải là hiếm.

Một số giải pháp phát hiện khi khách hàng thiếu một số thông tin quá lâu và bắt đầu đồng bộ hóa, có thể sử dụng UDP hoặc TCP.

Một cách tiếp cận phổ biến khác là thiết kế truyền thông sao cho nó hoàn toàn không dựa vào sự thừa nhận, nhưng điều đó nằm ngoài phạm vi của câu hỏi.


3

Trong RTS, bạn thực sự không thể sử dụng giao thức như TCP và bạn cũng không thể làm cho UDP đáng tin cậy. Nếu bạn cố gắng, trò chơi sẽ đóng băng bất cứ khi nào có mạng.

Thay vào đó, bạn thiết kế giao thức sao cho các gói bị bỏ lỡ không quá quan trọng.

Các phiên bản ngắn là bạn không quan tâm nơi các cầu thủ khác là khung cuối cùng miễn là bạn biết họ đang ở đâu tại . Phiên bản dài phức tạp hơn.

Câu hỏi sau đó trở thành, bạn sẽ làm gì khi một gói bị mất? Và câu trả lời là ... bạn đoán. Người chơi có thể đang di chuyển trên một đường thẳng, phải không? Chỉ cần di chuyển chúng một bước xa hơn dọc theo dòng đó. ... Ngoại trừ không có người chơi RTS nào di chuyển trên một đường thẳng. Và sau đó là phát hiện va chạm.

Điều này thật khó. Nhiều trò chơi nhận được nó sai. Có thể lập luận rằng không có câu trả lời đúng cho vấn đề này, chỉ có những sai lầm khác nhau có thể được đánh đổi.

Lý do những trò chơi này hoạt động khá tốt không chỉ là họ đã suy nghĩ lâu dài và chăm chỉ về những vấn đề này, mà còn là Internet đã trở nên khá đáng tin cậy. Hầu như tất cả các gói UDP thực sự đến đích của họ một cách kịp thời. (Trừ khi có sự cố vĩnh viễn như tường lửa)


Warcraft 3 sử dụng TCP.
fsp
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.