ก่อนอื่นถ้าคุณมีบางสิ่งบางอย่างและมันใช้งานได้ปกติแล้วคุณควรปล่อยให้เป็นอย่างนั้น ทำไมต้องแก้ไขสิ่งที่ไม่เสียหาย
แต่ถ้าคุณมีปัญหาและอยากจะเขียนรหัสเครือข่ายของคุณใหม่อีกครั้งฉันคิดว่าคุณมีตัวเลือกหลัก ๆ สี่อย่าง:
- รหัสบล็อกแบบมัลติเธรด (สิ่งที่คุณกำลังทำอยู่ตอนนี้)
- ซ็อกเก็ตที่ไม่ปิดกั้นพร้อมการแจ้งเตือนระดับที่เรียก
- ซ็อกเก็ตที่ไม่ปิดกั้นพร้อมการแจ้งเตือนการเปลี่ยนแปลงความพร้อม
- ซ็อกเก็ตแบบอะซิงโครนัส
การเขียนไคลเอนต์และเซิร์ฟเวอร์จำนวนมาก (จากเพียร์ทูเพียร์ไปจนถึงผู้เล่นหลายคนอย่างหนาแน่น) ฉันคิดว่าตัวเลือกที่ 2 นำไปสู่ความซับซ้อนน้อยที่สุดพร้อมประสิทธิภาพที่ดีทั้งในส่วนของเซิร์ฟเวอร์และไคลเอนต์ของเกม ในอีกไม่ช้าฉันจะใช้ตัวเลือก 4 แต่โดยปกติแล้วคุณจะต้องคิดใหม่โปรแกรมทั้งหมดและส่วนใหญ่ฉันคิดว่ามันมีประโยชน์สำหรับเซิร์ฟเวอร์ไม่ใช่ลูกค้า
โดยเฉพาะอย่างยิ่งฉันต้องการแนะนำให้บล็อกซ็อกเก็ตในสภาพแวดล้อมแบบมัลติเธรดเนื่องจากการทำเช่นนั้นมักจะนำไปสู่การล็อคและคุณสมบัติการซิงโครไนซ์อื่น ๆ ซึ่งไม่เพียงเพิ่มความซับซ้อนของรหัสเท่านั้น คนอื่น ๆ
แต่เหนือสิ่งอื่นใดการใช้งานซ็อกเก็ตส่วนใหญ่ (และการใช้งาน I / O ส่วนใหญ่ ณ เวลานั้น) จะไม่ถูกบล็อกในระดับต่ำสุด การดำเนินการบล็อกนั้นมีไว้เพื่อทำให้การพัฒนาโปรแกรมง่ายขึ้นเล็กน้อย เมื่อซ็อกเก็ตปิดกั้น CPU ในเธรดนั้นไม่มีการใช้งานอย่างสมบูรณ์ดังนั้นเหตุใดจึงสร้างสิ่งที่เป็นนามธรรมที่ไม่มีการปิดกั้นการบล็อกสิ่งที่เป็นนามธรรมมากกว่างานที่ไม่ได้ปิดกั้นอยู่แล้ว
การเขียนโปรแกรมซ็อกเก็ตที่ไม่มีการปิดกั้นนั้นค่อนข้างน่ากังวลหากคุณยังไม่ได้ลองใช้ แต่กลับกลายเป็นว่ามันค่อนข้างง่ายและถ้าคุณกำลังทำโพลอินพุตอยู่คุณมีความคิดที่จะทำซ็อกเก็ตที่ไม่บล็อก
สิ่งแรกที่คุณต้องทำคือตั้งค่าซ็อกเก็ตเป็นแบบไม่บล็อก คุณทำอย่างนั้นกับfcntl()
คุณทำด้วย
หลังจากนั้นก่อนที่จะทำsend()
, recv()
, sendto()
, recvfrom()
, accept()
( connect()
เป็นที่แตกต่างกันบิต) หรือสายอื่น ๆ ที่สามารถป้องกันด้ายคุณเรียกselect()
บนซ็อกเก็ตselect()
แจ้งให้คุณทราบว่าการดำเนินการอ่านหรือเขียนที่ตามมาสามารถทำได้บนซ็อกเก็ตโดยไม่บล็อกหรือไม่ หากเป็นกรณีนี้คุณสามารถดำเนินการตามที่คุณต้องการได้อย่างปลอดภัยและซ็อกเก็ตจะไม่บล็อก
รวมถึงสิ่งนี้ในเกมค่อนข้างง่าย หากคุณมีวนซ้ำเกมอยู่แล้วเช่นนี้:
while game_is_running do
poll_input()
update_world()
do_sounds()
draw_world()
end
คุณสามารถเปลี่ยนเป็นแบบนี้ได้:
while game_is_running do
poll_input()
read_network()
update_world()
do_sounds()
write_network()
draw_world()
end
ที่ไหน
function read_network()
while select(socket, READ) do
game.net_input.enqueue(recv(socket))
end
end
และ
function write_network()
while not game.net_output.empty and select(socket, WRITE) do
send(socket, game.net_output.dequeue())
end
end
ในแง่ของทรัพยากรหนังสือเล่มเดียวที่ฉันคิดว่าทุกคนต้องมีในชั้นหนังสือแม้ว่าจะเป็นหนังสือเล่มเดียวที่พวกเขามีคือ " Unix Network Programming, Vol 1 " โดย Richard Stevens ปลายปี ไม่สำคัญว่าคุณใช้ Windows หรือระบบปฏิบัติการอื่นหรือการเขียนโปรแกรมซ็อกเก็ตภาษา อย่าคิดว่าคุณเข้าใจซ็อกเก็ตจนกว่าคุณจะอ่านหนังสือเล่มนี้
แหล่งข้อมูลอื่นที่คุณสามารถค้นหาภาพรวมทั่วไปของโซลูชันที่มีในแง่ของการเขียนโปรแกรมซ็อกเก็ตหลายรายการ (ส่วนใหญ่เกี่ยวข้องกับการเขียนโปรแกรมเซิร์ฟเวอร์) คือหน้านี้