Saya mengalami beberapa masalah dengan Java socket API. Saya mencoba menampilkan jumlah pemain yang saat ini terhubung ke game saya. Mudah untuk menentukan kapan seorang pemain telah terhubung. Namun, tampaknya sulit untuk menentukan kapan seorang pemain telah memutus sambungan menggunakan API soket.
Memanggil isConnected()
pada soket yang telah dicabut dari jarak jauh sepertinya selalu kembali true
. Demikian pula, memanggil isClosed()
soket yang telah ditutup dari jarak jauh sepertinya selalu kembali false
. Saya telah membaca bahwa untuk benar-benar menentukan apakah soket telah ditutup atau tidak, data harus ditulis ke aliran keluaran dan pengecualian harus ditangkap. Ini sepertinya cara yang sangat tidak bersih untuk menangani situasi ini. Kami hanya harus terus-menerus mengirim pesan sampah melalui jaringan untuk mengetahui kapan soket telah ditutup.
Apakah ada solusi yang lain?
sumber
0
bukan-1
.Ini adalah praktik umum dalam berbagai protokol perpesanan untuk menjaga detak jantung satu sama lain (tetap mengirim paket ping) paket tidak perlu berukuran sangat besar. Mekanisme probing akan memungkinkan Anda untuk mendeteksi klien yang terputus bahkan sebelum TCP mengetahuinya secara umum (batas waktu TCP jauh lebih tinggi) Kirim probe dan tunggu katakanlah 5 detik untuk balasan, jika Anda tidak melihat balasan untuk katakanlah 2-3 probe berikutnya, pemutar Anda terputus.
Juga, pertanyaan terkait
sumber
Saya melihat jawaban lain baru saja diposting, tetapi saya pikir Anda interaktif dengan klien yang memainkan game Anda, jadi saya dapat mengajukan pendekatan lain (sementara BufferedReader jelas valid dalam beberapa kasus).
Jika Anda ingin ... Anda dapat mendelegasikan tanggung jawab "pendaftaran" kepada klien. Yaitu Anda akan memiliki kumpulan pengguna yang terhubung dengan stempel waktu pada pesan terakhir yang diterima dari masing-masing ... jika waktu klien habis, Anda akan memaksa pendaftaran ulang klien, tetapi itu mengarah ke kutipan dan ide di bawah ini.
Jika kode Java Anda tidak menutup / memutuskan Socket, bagaimana lagi Anda akan diberitahu bahwa remote host menutup koneksi Anda? Pada akhirnya, coba / tangkap Anda melakukan hal yang kira-kira sama dengan yang dilakukan oleh poller yang mendengarkan peristiwa di soket AKTUAL. Pertimbangkan hal berikut:
Saya rasa salah satu fitur bahasa yang diabstraksi adalah Anda diabstraksi dari detail. Pikirkan penggunaan kata kunci di C # (coba / akhirnya) untuk SqlConnection atau apa pun ... itu hanya biaya melakukan bisnis ... Saya pikir coba / tangkap / akhirnya adalah pola yang diterima dan diperlukan untuk penggunaan Socket.
sumber
Saya pikir ini adalah sifat koneksi tcp, dalam standar itu dibutuhkan sekitar 6 menit keheningan dalam transmisi sebelum kami menyimpulkan bahwa koneksi keluar hilang! Jadi menurut saya Anda tidak dapat menemukan solusi yang tepat untuk masalah ini. Mungkin cara yang lebih baik adalah dengan menulis beberapa kode praktis untuk menebak kapan server seharusnya menganggap koneksi pengguna ditutup.
sumber
Seperti yang dikatakan @ user207421, tidak ada cara untuk mengetahui status koneksi saat ini karena Model Arsitektur Protokol TCP / IP. Jadi server harus memperhatikan Anda sebelum menutup koneksi atau Anda memeriksanya sendiri.
Ini adalah contoh sederhana yang menunjukkan bagaimana mengetahui soket ditutup oleh server:
sockAdr = new InetSocketAddress(SERVER_HOSTNAME, SERVER_PORT); socket = new Socket(); timeout = 5000; socket.connect(sockAdr, timeout); reader = new BufferedReader(new InputStreamReader(socket.getInputStream()); while ((data = reader.readLine())!=null) log.e(TAG, "received -> " + data); log.e(TAG, "Socket closed !");
sumber
Saya menghadapi masalah serupa. Dalam kasus saya, klien harus mengirim data secara berkala. Saya harap Anda memiliki persyaratan yang sama. Kemudian saya mengatur SO_TIMEOUT
socket.setSoTimeout(1000 * 60 * 5);
yang melemparjava.net.SocketTimeoutException
ketika waktu yang ditentukan telah habis. Kemudian saya dapat mendeteksi klien mati dengan mudah.sumber
Begitulah cara saya menanganinya
while(true) { if((receiveMessage = receiveRead.readLine()) != null ) { System.out.println("first message same :"+receiveMessage); System.out.println(receiveMessage); } else if(receiveRead.readLine()==null) { System.out.println("Client has disconected: "+sock.isClosed()); System.exit(1); } }
jika result.code == null
sumber
readLine()
dua kali. Anda sudah tahu bahwaelse
blok itu nol .Di Linux ketika menulis () ke dalam soket yang sisi lain, tidak Anda ketahui, tertutup akan memicu sinyal / pengecualian SIGPIPE bagaimanapun Anda ingin memanggilnya. Namun jika Anda tidak ingin ketahuan oleh SIGPIPE Anda dapat menggunakan send () dengan flag MSG_NOSIGNAL. Panggilan send () akan kembali dengan -1 dan dalam hal ini Anda dapat memeriksa errno yang akan memberitahu Anda bahwa Anda mencoba menulis pipa yang rusak (dalam hal ini soket) dengan nilai EPIPE yang menurut errno.h setara dengan 32. Sebagai reaksi terhadap EPIPE Anda dapat menggandakan kembali dan mencoba membuka kembali soket dan mencoba mengirimkan informasi Anda lagi.
sumber
send()
panggilan akan kembali -1 hanya jika data keluar mendapat buffered cukup lama untuk timer kirim berakhir. Ini hampir pasti tidak akan terjadi pada pengiriman pertama setelah terputus, karena buffering di kedua ujungnya dan sifat asinkronsend()
di balik terpal.