การแลกเปลี่ยนข้อความไคลเอนต์เซิร์ฟเวอร์เซิร์ฟเวอร์และการซิงโครไนซ์นาฬิกา


10

ฉันกำลังทำเกมฟิสิกส์ที่รวดเร็วซึ่งเป็นตารางฮอกกี้ ด้วยค้อนสองตัวและลูกซนหนึ่งตัว เกมทำงานบน iphone / ipad และฉันกำลังเล่นเกมหลายคนผ่าน GameCenter

นี่คือการทำงานของระบบเครือข่าย ลูกค้าที่เป็นดาวจับคู่จะถูกตัดสินในฐานะเซิร์ฟเวอร์และลูกค้าที่ยอมรับคำขอแข่งขันคือลูกค้า

'เซิร์ฟเวอร์' มีการทำงานของฟิสิกส์และการตอบสนองนั้นเกิดขึ้นทันทีและไคลเอนต์ก็มีการทำงานของฟิสิกส์เพื่อให้ดูราบรื่นระหว่างการแลกเปลี่ยนข้อความ สิ่งที่ฉันทำในฐานะเซิร์ฟเวอร์คือฉันส่งไปยังลูกค้าความเร็วลูกตุ้มของฉันและตำแหน่งของฉันและลูกค้าปรับความเร็ว / ตำแหน่งเด็กซนของเขาที่เกี่ยวข้องกับเซิร์ฟเวอร์เพื่อให้มันซิงค์ ไม่เช่นนั้นฟิสิกส์จะซิงโครไนซ์และมันไขสกรูขึ้น

เมื่อเวลาในการตอบสนองของเครือข่ายดีผล 100 มิลลิวินาทีนั้นค่อนข้างดีฉันได้เกมที่เล่นได้อย่างราบรื่นทางฝั่งไคลเอ็นต์และพฤติกรรมแปลก ๆ นั้นน้อยที่สุด ปัญหาเกิดขึ้นเมื่อความล่าช้าอยู่ที่ประมาณ 150 ถึง 200ms ในกรณีดังกล่าวเกิดขึ้นที่ลูกค้าของฉันเด็กซนชนขอบและทิศทางกลับหัว แต่มันได้รับข้อความล่าช้าจากเซิร์ฟเวอร์และมันกลับเล็กน้อยทำให้เกิดความรู้สึกแปลก ๆ กับพฤติกรรมลูก

ฉันได้อ่านบางสิ่งเกี่ยวกับเรื่องนี้:

โป่งเครือข่ายตัวอย่าง

คลิกตัวอย่างการซิงโครไนซ์

Wikipedia เกี่ยวกับ Clock Sync

ดังนั้นฉันจะแก้ปัญหานี้อย่างไร เท่าที่ฉันได้อ่านตัวเลือกที่ดีที่สุดที่ฉันต้องทำคือการซิงโครไนซ์นาฬิกาบนเซิร์ฟเวอร์ / ไคลเอ็นต์ด้วยการประทับเวลาเพื่อที่เมื่อฉันได้รับข้อความหน่วงเวลาที่เกี่ยวข้องกับนาฬิกาของฉันฉันก็ไม่สนใจแล้วปล่อยให้ลูกค้าจำลอง งาน. พวกคุณเห็นด้วยไหม? และเนื่องจากฉันกำลังส่งข้อมูลที่ไม่น่าเชื่อถือ (UDP) ฉันอาจได้รับข้อความหรือข้อความล่าช้า

หากเป็นวิธีที่ดีที่สุดฉันจะใช้การซิงโครไนซ์นาฬิกาได้อย่างไร ฉันอ่านขั้นตอนเกี่ยวกับวิธีการ แต่ฉันไม่เข้าใจมันมากนัก

มันบอกว่า:

  1. ลูกค้าประทับเวลาท้องถิ่นปัจจุบันบนแพ็กเก็ต "คำขอเวลา" และส่งไปยังเซิร์ฟเวอร์
  2. เมื่อได้รับจากเซิร์ฟเวอร์เซิร์ฟเวอร์จะประทับตราเวลาและส่งคืน
  3. เมื่อลูกค้าได้รับลูกค้าจะลบเวลาปัจจุบันจากเวลาที่ส่งและหารด้วยสองเพื่อคำนวณเวลาแฝง มันลบเวลาปัจจุบันจากเวลาเซิร์ฟเวอร์เพื่อกำหนดเดลตาเวลาไคลเอนต์ - เซิร์ฟเวอร์และเพิ่มครึ่งเวลาในการรับเดลต้านาฬิกาที่ถูกต้อง (จนถึงตอนนี้ algothim นี้คล้ายกับ SNTP มาก)
  4. ไคลเอนต์ทำซ้ำขั้นตอนที่ 1 ถึง 3 ห้าหรือมากกว่าครั้งหยุดสองสามวินาทีในแต่ละครั้ง การรับส่งข้อมูลอื่นอาจได้รับอนุญาตในระหว่างกาล แต่ควรย่อให้เล็กสุดเพื่อผลลัพธ์ที่ดีที่สุดผลลัพธ์ของการรับแพ็คเก็ตจะถูกสะสมและเรียงลำดับในเวลาแฝงต่ำสุดถึงลำดับสูงสุดเวลาแฝงสูงสุด ค่ามัธยฐานแฝงถูกกำหนดโดยการเลือกตัวอย่างจุดกลางจากรายการสั่งซื้อนี้
  5. ตัวอย่างทั้งหมดข้างต้นประมาณ 1 ส่วนเบี่ยงเบนมาตรฐานจากค่ามัธยฐานจะถูกละทิ้งและตัวอย่างที่เหลือจะถูกเฉลี่ยโดยใช้ค่าเฉลี่ยเลขคณิต

ทำตามตัวอย่างนี้ฉันจะได้:

ทำให้เกมดังกล่าวโหลดแล้วและเวลาไคลเอ็นต์ของฉันคือ 0 ตอนนี้ดังนั้นฉันส่งไปยังเซิร์ฟเวอร์ว่าเวลาของฉันคือ 0

ข้อความใช้เวลา 150ms เพื่อไปยังเซิร์ฟเวอร์ แต่นาฬิกาของเซิร์ฟเวอร์เริ่มต้นแล้วและเป็น 1 วินาทีก่อนหน้าไคลเอ็นต์ เมื่อเซิร์ฟเวอร์ได้รับข้อความเวลาจะเป็น: 1.15 และส่งเวลานั้นไปยังลูกค้าเราดีหรือไม่? ปล่อยให้ความล่าช้าของเราอยู่ที่ 150ms

ตอนนี้ไคลเอนต์ได้รับเวลา 1.15 และลบเวลาปัจจุบันจากเวลาที่ส่งและหารด้วยสองเพื่อคำนวณเวลาแฝง ซึ่งคือ: 0.3 - 0 = 0.3 / 2 -> 150ms

มันลบเวลาปัจจุบันจากเวลาเซิร์ฟเวอร์เพื่อกำหนดเดลตาเวลาไคลเอนต์ - เซิร์ฟเวอร์และเพิ่มครึ่งเวลาในการรับเดลต้านาฬิกาที่ถูกต้อง:
เวลาไคลเอ็นต์: 0.3 เวลาเซิร์ฟเวอร์ 1.15
0.3 - 1.15 = .85 + เวลาแฝง (.15) = 1

การซิงโครไนซ์เป็นอย่างไร ฉันกำลังคิดถึงอะไร

เป็นครั้งแรกของฉันที่ได้รับประสบการณ์ผู้เล่นหลายคนและเครือข่ายดังนั้นฉันจึงสับสนเล็กน้อย

ขอบคุณ.


คำถามที่ดี. คุณสามารถแก้ไข: 0.3 - 1.15 เป็น 1.15 - 0.3 ได้หรือไม่
Ciaran

คำตอบ:


12

อัลกอริทึมที่โพสต์นั้นถูกต้อง แต่ในตัวอย่างของคุณคุณลืมเวลาที่เซิร์ฟเวอร์แพ็คเก็ตไปถึงลูกค้าดังนั้น:

Server time: 1
Client time: 0
Client sends 0 to server

... 150ms to get to server  (ping is 300! not 150ms in this case. Ping is round-trip)

Server time: 1.15
Client time: 0.15
Server receives packet and sends client 1.15

... 150ms to get back to client

Server time: 1.30
Client time: 0.30
Client receives 1.15 from server

อย่างที่คุณเห็นถ้าลูกค้าเปลี่ยนนาฬิกาเป็น 1.15 มันจะอยู่หลังเซิร์ฟเวอร์ 0.15 นี่คือสาเหตุที่คุณต้องปรับปิง (aka Round Trip Time [RTT]) นี่คือการคำนวณเวลาเดลต้าเต็มรูปแบบที่ทำได้หลายขั้นตอน:

Server Time - Current Time + Ping / 2
= Server Time - Current Time + (Current Time - First Packet Time) / 2
= 1.15 (Perceived, not actual!) - 0.30 + (0.30 - 0.00) / 2
= 1.00

สิ่งนี้ทำให้เรามีเวลาเดลต้าที่ถูกต้องเป็น 1.00 วินาที


ฉันได้รับมันดังนั้นนาฬิกาลูกค้าของฉันคือ 1.00 และเซิร์ฟเวอร์คือ 1.30 หลังจากฉันได้รับข้อความจากเซิร์ฟเวอร์ฉันต้องเพิ่ม ping เพื่อตรวจสอบว่าเป็นข้อความที่ล่าช้าหรืออะไร? อีกสิ่งหนึ่งจะเกิดอะไรขึ้นถ้าเวลาในการตอบสนองมีการเปลี่ยนแปลงฉันต้องทำ calcs เหล่านั้นตลอดเวลาหรือไม่
gmemario

เวลาเดลต้า 1.00s จะถูกเพิ่มลงในนาฬิกาปัจจุบันเพื่อให้เวลาของลูกค้าเท่ากับเวลาของเซิร์ฟเวอร์ เวลาแฝงเปลี่ยนแปลงอยู่เสมอแต่ละแพ็กเก็ตจะมี RTT แตกต่างกันเล็กน้อย ในช่วงเวลาสั้น ๆ เช่นในเกมฉันจะซิงค์ครั้งนี้เพียงครั้งเดียวลูกค้าจะเดาได้ดีว่าเวลาของเซิร์ฟเวอร์คืออะไรและนาฬิกาทั้งสองควรจะเดินไปข้างหน้าด้วยความเร็วเท่ากัน ข้อยกเว้นเพียงอย่างเดียวคือถ้าคุณได้รับแพ็คเก็ตที่ดูเหมือนจะมาจากอนาคต ในกรณีนั้นมี 2 วิธีแก้ไข: 1) ทำการซิงค์เวลาใหม่ 2) เลื่อนนาฬิกาของคุณให้ตรงกับนาฬิกาในอนาคต
John McDonald

ตกลงให้ดูที่สถานการณ์นี้เพื่อให้แน่ใจว่าฉันเข้าใจแล้ว: เวลาของเซิร์ฟเวอร์: เวลาไคลเอ็นต์ 1 วินาที: 0 วินาที 150 มิลลิวินาทีในการไปยังเซิร์ฟเวอร์เวลาเซิร์ฟเวอร์: 1.15 วินาทีไคลเอนต์: 0.15 วินาทีเซิร์ฟเวอร์ส่งไคลเอนต์ 1.15s 200ms เพื่อไปยังไคลเอนต์ ดังนั้นปิงของฉันตอนนี้คือ 350 มิลลิวินาที ถูกต้องหรือไม่ เวลาเซิร์ฟเวอร์: 1.35 เวลาไคลเอนต์: 0.35 การทำ calcs: 1.15 - .35 + (0.35 - 0.00) / 2 ตอนนี้ deltaTime ของฉัน = 0,975 ถ้าฉันเพิ่มเวลาเดลต้า 0,975 ของฉัน. 35 ฉันได้รับ: 1,325 ซึ่งเป็น desync ถูกต้องหรือไม่
gmemario

@ Gilson นั่นถูกต้อง หากเวลาแฝงสำหรับแพ็กเก็ตทั้งสองนั้นแตกต่างกัน (รับประกันได้เกือบ) การคำนวณเวลาเดลต้าของลูกค้าจะไม่สมบูรณ์แบบ ไม่มีทางที่ลูกค้าจะสมบูรณ์แบบได้ ในอัลกอริทึมที่คุณอธิบายไว้ในคำถามเวลาของเดลต้าจะถูกคำนวณจำนวนครั้งและมีวิธีสำหรับการเลือกและเฉลี่ยค่าผลลัพธ์เหล่านี้ วิธีการซิงค์หลายครั้งจะทำอะไรแบบนี้ แต่โดยทั่วไปมักใช้กับเซิร์ฟเวอร์ที่สำคัญต่อธุรกิจและเซิร์ฟเวอร์ที่ใช้งานมานานเช่นการแลกเปลี่ยนหุ้น สำหรับความแม่นยำของเวลาที่คุณต้องการสำหรับเกมสั้น ๆ ฉันคิดว่ามันจะเกินกำลัง
John McDonald

@Gilson ตราบใดที่ลูกค้ามีการประมาณเวลาที่เหมาะสมของเซิร์ฟเวอร์และนาฬิกาทั้งสองเดินหน้าไปข้างหน้าด้วยอัตราเดียวกันคุณไม่ควรสังเกตเห็นปัญหาใด ๆ เมื่อไคลเอนต์หรือเซิร์ฟเวอร์ส่งการกระทำไปอีกด้านหนึ่งพวกเขาจะส่งเวลาท้องถิ่น ในด้านการรับข้อความควรอยู่ในอดีตเสมอและจะต้องตีความว่าเป็นเหตุการณ์ที่ผ่านมา ซึ่งหมายความว่าคุณต้องการข้อมูลทั้งหมดในแพ็คเก็ตเช่นตำแหน่งความเร็ว (ขนาด + ทิศทาง) และเวลา จากนั้นคุณสามารถวางเด็กซนที่นั่นและจากนั้นย้ายเด็กซนจากอดีตไปยังปัจจุบัน ฉันอยู่ในการแชท btw
John McDonald
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.