Pertanyaan OutputStream.write () berhasil tetapi data tidak terkirim [tertutup]


Saya memiliki perilaku yang sangat aneh saat menulis ke soket. Di klien seluler saya, saya menggunakan soket yang diinisialisasi sebagai berikut:

private void initSocket()
{
    socket = new Socket();
    socket.connect(new InetSocketAddress(host, port));

    os = new DataOutputStream(socket.getOutputStream());
    is = new DataInputStream(socket.getInputStream());
}

kemudian secara berkala (setiap 60 detik) saya membaca dan menulis beberapa data ke soket ini (kode di sini sedikit disederhanakan):

if(!isSocketInitialized())
{
    initSocket();
}

byte[] msg = getMessage();

os.write(msg);
os.flush();

int bytesAvailable = is.available( );
if(bytesAvailable>0)
{
    byte[] inputBuffer = new byte[bytesAvailable];

    int numRead = is.read(inputBuffer, 0, bytesAvailable);
    processServerReply(inputBuffer, numRead);
}

Dan itu berhasil. Tapi ... Terkadang (sangat jarang, mungkin 1 atau 2 kali per hari) server saya tidak menerima data. Log klien saya terlihat seperti:

Written A
Written B
Written C
Written D
Written E

dan seterusnya. Tapi di sisi server sepertinya:

Received A
Received E

Catatan data B, C, D tidak diterima, meskipun pada sisi klien terlihat semua data dikirim tanpa pengecualian!

Kesenjangan seperti itu bisa kecil (2-3 menit) yang tidak terlalu buruk, tetapi kadang-kadang bisa sangat besar (1-2 jam = 60-120 siklus) dan itu benar-benar masalah bagi pelanggan saya.

Saya benar-benar tidak tahu apa yang bisa salah. Data tampaknya dikirim oleh klien, tetapi tidak pernah sampai di sisi server. Saya sudah memeriksanya juga dengan proxy.

Saya hanya memiliki log dan saya tidak dapat mereproduksi masalah ini (tetapi itu terjadi kepada pelanggan saya lebih dari satu kali setiap hari) dan dalam log terkadang saya melihat bahwa koneksi rusak dengan Pengecualian "kirim ke gagal: ECONNRESET (Koneksi disetel ulang oleh rekan ) ". Setelah itu program menutup soket, menginisialisasi ulang:

// close
is.close();
os.close();
socket.close();

// reinitialize
initSocket();

dan mencoba menulis data lagi seperti yang dijelaskan di atas. Kemudian saya melihat masalahnya: koneksi terjalin, menulis berhasil, tetapi TIDAK ADA DATA tiba di server!

Mungkin itu ada hubungannya dengan ECONNRESET mungkin tidak, tapi saya ingin menyebutkan ini karena mungkin itu penting.

Saya akan sangat berterima kasih untuk semua ide dan tips.

P.S. Mungkin itu memainkan beberapa peran: kode klien berjalan pada perangkat seluler Android yang bergerak (di dalam mobil). Koneksi internet didirikan melalui GPRS.


UPD: Saya bisa mereproduksinya! Setidaknya sebagian (klien mengirim A, B, C, D, E dan server hanya menerima A). Itu terjadi setiap saat jika:

  1. Koneksi terjalin, klien membaca dan menulis -> OK

  2. Koneksi terputus (saya mematikan router WLAN saya :)), saya menjadi IOException, saya menutup aliran dan soket -> OK

  3. Saya menyalakan router saya, koneksi kembali, saya menginisialisasi soket lagi, program mengeksekusi write () tanpa pengecualian, tapi ... tidak ada data yang masuk ke server.

BTW karena koneksi kembali lagi tersedia () mengembalikan selalu 0.


9
2017-10-25 19:52


asal


Jawaban:


Singkirkan available() uji. Jika rekan kira untuk membalas, baca saja. Jika tidak, terkadang Anda akan membaca balasannya dan terkadang tidak, dan Anda akan tidak sinkron. Ada sangat sedikit penggunaan yang benar available(), dan ini bukan salah satunya.


2
2017-10-25 22:23



Penyebab perilaku aneh ini adalah soket yang tidak tertutup di sisi server. Saya dapat mereproduksinya dengan klien kecil dan server. Keduanya terdiri dari beberapa baris kode, yang melakukan hal berikut:

  1. terhubung ke server
  2. mensimulasikan titik mati (mis. mematikan WiFi Anda)
  3. tutup soket di sisi klien
  4. JANGAN TUTUP soket di sisi server
  5. nyalakan WiFi Anda
  6. buat koneksi baru dari klien
  7. menulis data ke koneksi ini

Voila! Klien menulis data tanpa kesalahan, tetapi server tidak menerimanya ...

Tetapi jika server menutup soket juga, maka server dapat membaca data ini. Jadi solusinya harus menutup soket setelah waktu habis di sisi server.

Sayangnya dalam kasus saya itu tidak layak, karena server adalah perangkat lunak pihak ketiga milik.


1
2017-11-19 18:19