Tamam, her şeyden önce, eğer bir şeyiniz varsa ve işe yarıyorsa, bunu böyle bırakmak genellikle iyi bir fikirdir. Kırılmayan şeyi neden düzeltmeliyim?
Ancak sorun yaşıyorsanız ve gerçekten ağ kodunuzu yeniden yazmak istiyorsanız, dört ana seçeneğiniz olduğunu düşünüyorum:
- Çok iş parçacıklı engelleme kodu (şu anda ne yapıyorsunuz)
- Seviye tetiklemeli bildirim ile tıkanmayan soketler
- Hazırlık değişikliği bildirimi ile tıkanmayan soketler
- Asenkron prizler
Çok sayıda çok oyunculu (eşler arasıdan çok oyunculuya kadar) çok sayıda istemci ve sunucu yazdıktan sonra, seçenek 2'nin oyunun hem sunucu hem de istemci bölümleri için oldukça iyi performansla en az karmaşıklığa yol açtığını düşünüyorum. Yakın bir saniye olarak, seçenek 4 ile giderdim, ancak bu genellikle tüm programınızı yeniden düşünmenizi gerektirir ve çoğunlukla istemciler için değil sunucular için yararlı buluyorum.
Özellikle, çok iş parçacıklı bir ortamda soketlerin engellenmesine karşı tavsiyede bulunmak istiyorum, çünkü bunu yapmak genellikle kodun karmaşıklığını büyük ölçüde artırmakla kalmayıp aynı zamanda bazı iş parçacıkları bekledikçe performansını da düşürebilen kilitleme ve diğer senkronizasyon özelliklerine yol açar. diğerleri.
Ancak tüm bunların ötesinde, çoğu soket uygulaması (ve oradaki çoğu G / Ç uygulaması) en düşük düzeyde engellemez. Önemsiz programların geliştirilmesini basitleştirmek için engelleme işlemleri basitçe sağlanır. Bir soket bloke olduğunda, o iş parçacığındaki CPU tamamen boşta, o zaman neden zaten engellemeyen bir görev üzerinde engelleme soyutlaması üzerinde engellemeyen bir soyutlama oluştursun?
Engellemeyen soket programlama, denemediyseniz biraz yıldırıcıdır, ancak oldukça basittir ve zaten giriş yoklaması yapıyorsanız, engellemeyen soketler yapmak için zaten zihniniz var.
Yapmak istediğiniz ilk şey soketi engellemeyecek şekilde ayarlamaktır. Bunu ile yaparsın fcntl()
.
Bundan sonra, bunu yapmadan önce send()
, recv()
, sendto()
, recvfrom()
, accept()
( connect()
çağrı, iplik engelleyebilir veya diğer aramalar biraz farklıdır) select()
soket üzerinde. select()
sonraki bir okuma veya yazma işleminin soket üzerinde engellemeden gerçekleştirilip gerçekleştirilemeyeceğini bildirir. Bu durumda, istediğiniz işlemi güvenli bir şekilde yapabilirsiniz ve soket bloke olmaz.
Bunu bir oyuna dahil etmek oldukça basittir. Zaten bir oyun döngünüz varsa, örneğin şöyle:
while game_is_running do
poll_input()
update_world()
do_sounds()
draw_world()
end
şöyle görünecek şekilde değiştirebilirsiniz:
while game_is_running do
poll_input()
read_network()
update_world()
do_sounds()
write_network()
draw_world()
end
nerede
function read_network()
while select(socket, READ) do
game.net_input.enqueue(recv(socket))
end
end
ve
function write_network()
while not game.net_output.empty and select(socket, WRITE) do
send(socket, game.net_output.dequeue())
end
end
Kaynaklar açısından, herkesin kitap raflarında olması gerektiğini düşündüğüm tek kitap, sahip oldukları tek kitap olsa bile , Richard Stevens'ın sonundaki " Unix Network Programming, Cilt 1 " dir. Windows veya başka bir işletim sistemi veya dil soketi programlama yapmanız önemli değildir. Bu kitabı okuyana kadar soketleri anladığınızı düşünmeyin.
Çok soketli programlama (çoğunlukla sunucu programlama ile ilgilidir) açısından mevcut çözümlere genel bir bakış bulabileceğiniz başka bir kaynak bu sayfadır .