Oke, pertama-tama, jika Anda memiliki sesuatu dan berfungsi, biasanya ide yang baik untuk membiarkannya seperti itu. Mengapa memperbaiki apa yang tidak rusak?
Tetapi jika Anda mengalami masalah, dan ingin menulis ulang kode jaringan Anda, saya pikir Anda memiliki empat pilihan utama:
- Kode pemblokiran multithreaded (apa yang Anda lakukan saat ini)
- Soket yang tidak menghalangi dengan pemberitahuan yang dipicu oleh level
- Soket yang tidak menghalangi dengan pemberitahuan perubahan kesiapan
- Soket asinkron
Setelah menulis banyak klien dan server multiplayer (dari peer-to-peer ke multiplayer besar-besaran), saya suka berpikir bahwa opsi 2 mengarah pada kompleksitas paling sedikit, dengan kinerja yang cukup baik, baik untuk server dan bagian klien dari permainan. Sebagai penutup kedua, saya akan menggunakan opsi 4, tetapi itu biasanya mengharuskan Anda untuk memikirkan kembali seluruh program Anda, dan saya sebagian besar menganggapnya berguna untuk server dan bukan klien.
Secara khusus, saya ingin menyarankan agar tidak memblokir soket di lingkungan multithreaded, karena hal itu biasanya mengarah ke penguncian dan fitur sinkronisasi lainnya yang tidak hanya sangat meningkatkan kompleksitas kode, tetapi juga dapat menurunkan kinerjanya, karena beberapa thread menunggu lainnya.
Tetapi di atas semua itu, sebagian besar implementasi socket (dan sebagian besar implementasi I / O pada saat itu) adalah non-blocking pada level terendah. Operasi pemblokiran hanya disediakan untuk menyederhanakan pengembangan program-program sepele. Ketika soket memblokir, CPU di utas itu benar-benar idle, jadi mengapa membangun abstraksi non-blocking atas abstraksi blocking atas tugas yang sudah tidak memblokir?
Pemrograman soket non-blocking agak menakutkan jika Anda belum mencobanya, tetapi ternyata itu cukup sederhana, dan jika Anda sudah melakukan polling input, Anda sudah memiliki pola pikir untuk melakukan soket non-blocking.
Hal pertama yang ingin Anda lakukan adalah mengatur soket ke non-blocking. Anda melakukannya dengan fcntl()
.
Setelah itu, sebelum Anda melakukannya send()
, recv()
, sendto()
, recvfrom()
, accept()
( connect()
sedikit berbeda) atau panggilan lain yang bisa memblokir benang, Anda menelepon select()
pada soket. select()
memberi tahu Anda apakah operasi baca atau tulis selanjutnya dapat dilakukan pada soket tanpa memblokirnya. Jika itu yang terjadi, Anda dapat dengan aman melakukan operasi yang Anda inginkan, dan soket tidak akan menghalangi.
Termasuk ini dalam sebuah game cukup sederhana. Jika Anda sudah memiliki loop game, misalnya seperti ini:
while game_is_running do
poll_input()
update_world()
do_sounds()
draw_world()
end
Anda dapat mengubahnya agar terlihat seperti ini:
while game_is_running do
poll_input()
read_network()
update_world()
do_sounds()
write_network()
draw_world()
end
dimana
function read_network()
while select(socket, READ) do
game.net_input.enqueue(recv(socket))
end
end
dan
function write_network()
while not game.net_output.empty and select(socket, WRITE) do
send(socket, game.net_output.dequeue())
end
end
Dalam hal sumber daya, satu-satunya buku yang saya pikir harus dimiliki semua orang di rak buku mereka, bahkan jika itu satu-satunya buku yang mereka miliki, adalah " Unix Network Programming, Vol 1. " oleh almarhum Richard Stevens. Tidak masalah jika Anda melakukan pemrograman soket OS atau bahasa atau Windows lainnya. Jangan pikir Anda mengerti soket sampai Anda membaca buku ini.
Sumber lain di mana Anda dapat menemukan gambaran umum umum dari solusi yang tersedia dalam hal pemrograman banyak soket (kebanyakan relevan untuk pemrograman server) adalah halaman ini .
Anda tidak menulis bahasa pemrograman mana yang Anda gunakan, tetapi sebagian besar bahasa menyediakan kerangka kerja asinkron yang bagus yang sering menggunakan fitur-fitur sistem operasi yang mendasarinya.
Ketika Anda menulis implementasi berulir Anda sendiri berdasarkan soket pemblokiran (ingat: ketika Anda memiliki banyak klien, Anda memerlukan utas untuk setiap soket tunggal), Anda hanya akan menemukan kembali apa yang sudah disediakan oleh kerangka soket asinkron.
Jadi saya akan merekomendasikan Anda untuk menggunakan soket asinkron.
sumber
N
klien layanan thread ? Jika Anda memblokir, dan Anda ingin memastikan setiap soket memproses datanya terlepas dari status soket yang lain, Anda harus memiliki satu utas per soket. Itu, atau tidak menggunakan soket pemblokir.