mengelola koneksi soket di Java melalui tcp

Saya menulis klien yang pada dasarnya hanya membuka soket dan mengirim konten melalui koneksi. (kontennya mengikuti protokol Http)

Masalah yang saya hadapi berkaitan dengan pertanyaan - bagaimana dan kapan saya harus menutup koneksi. Masalahnya adalah koneksi terkadang ditutup terlalu dini ("FIN" dikirim ke server sebelum server menjawab).

dalam hal ini jawaban server hilang.
Saya mencoba menggunakan Thread.sleep sebelum menutup koneksi tetapi sepertinya tidak ada yang mempengaruhi waktu antara konten dikirim dan pesan "FIN" dikirim. (dilihat di Wireshark)

Jawabannya kadang sampai kadang tidak (kondisi balapan).

Bagaimana cara menunda pesan "FIN" agar saya tidak ketinggalan respons server?

saya menambahkan kelas yang relevan. Fungsi yang relevan adalah sendContentOverSocket

public class SocketClient {

           private String hostName;
           private int portNumber;
           private Socket ConnectionSocket;

           public void init(String hostName, int portNumber){
                          this.hostName = hostName;
                          this.portNumber = portNumber;
                          this.ConnectionSocket=createSocketConnection();

           }

           private Socket createSocketConnection() {
                          Socket socket = null;
                          try {
                                         socket = new Socket(this.hostName, this.portNumber);
                                         return socket;
                          } catch (UnknownHostException e) {
                                         e.printStackTrace();
                          } catch (IOException e) {
                                         e.printStackTrace();
                          }

                          return socket;
           }

           public void sendContentOverSocket(String content) {
                          try {
                                         PrintWriter out = new PrintWriter(
                                                                       ConnectionSocket.getOutputStream(), true);
                                         BufferedReader in = new BufferedReader(new InputStreamReader(
                                                                       ConnectionSocket.getInputStream()));
                                         out.print(content);

                                         try {
                                                        Thread.sleep(2000);
                                         } catch (InterruptedException e) {
                                                        // TODO Auto-generated catch block
                                                        e.printStackTrace();
                                         }

                                         out.close();
                                         in.close();                           
                                         ConnectionSocket.close();

                          } catch (IOException e) {
                                         e.printStackTrace();
                          }
           }

}

masukkan deskripsi gambar di sini


person mosh    schedule 23.03.2015    source sumber
comment
@ user1274820 Soket tidak 'ditutup dengan kesalahan' kecuali Anda melakukan kesalahan.   -  person user207421    schedule 23.03.2015


Jawaban (4)


TCP bekerja dengan konsep yang disebut setengah dekat. Ketika Anda menutup soket itu merupakan indikasi bahwa Anda tidak akan mengirim lagi. Dalam penjelasan Anda, saya melihat "FIN dikirim ke server sebelum server menjawab", jika Anda adalah kliennya, itu berarti Anda telah melakukan penutupan soket. Jika Anda mengharapkan hasil dari server dalam jangka waktu tertentu, Anda memerlukan semacam mekanisme pengaturan waktu, mungkin menggunakan pilihan yang dikombinasikan dengan batas waktu. Jika server menutup akhir koneksinya, Anda mendeteksinya dengan menerima byte yang diterima. Biasanya ini berarti Anda harus menutup stopkontaknya juga. Jadi kesimpulannya ada 3 alasan anda menutup stopkontak :

  • server menutup ujung soketnya pada dasarnya mengatakan saya tidak akan mengirim lagi
  • Anda telah menunggu beberapa saat dan Anda lelah menunggu dan memutuskan untuk menutup sendiri stopkontaknya.
  • kondisi kesalahan lainnya tetapi biasanya semuanya tampak seperti menerima 0 byte atau angka negatif.
person Philip Stuyck    schedule 23.03.2015
comment
terima kasih tapi bagaimana caranya menunggu sebentar? saya mencoba menggunakan mode tidur setelah mengirim pesan dan sebelum menutup koneksi tetapi tidak berfungsi seperti yang diharapkan. Anda dapat melihat pada gambar wireshark bahwa sleep (untuk beberapa alasan) dieksekusi sebelum Http dan bukan sebelum FIN dikirim. - person mosh; 23.03.2015
comment
Anda harus menggunakan api pilihan. Anda memilih dengan readset pada soket dan menentukan batas waktu katakanlah 10 detik. Select akan kembali jika data tersedia pada soket atau jika batas waktu telah habis. Jika sudah waktunya habis, tutup soketnya. - person Philip Stuyck; 23.03.2015
comment
Atau lebih tepatnya, karena ini adalah Socket, Anda menetapkan batas waktu baca dengan setSoTimeout() dan menangkap hasilnya. SocketTimeoutException. - person user207421; 24.03.2015

Tentu saja, Anda harus menutup koneksi setelah membaca jawabannya. Sulit untuk melihat misteri di sini. Tidak tidur. Jika Anda tidak membaca responsnya (a) Anda tidak dapat mengetahui apakah permintaan berhasil atau gagal, dan (b) server juga kemungkinan akan mengalami pengecualian.

Kode Anda berkualitas buruk. Semua metode tersebut harus menyebarkan pengecualian alih-alih menangkapnya secara internal dan mengembalikan null.

person user207421    schedule 23.03.2015
comment
ini hanyalah contoh singkat masalahnya. penanganan pengecualian telah ditangani. terima kasih. - person mosh; 23.03.2015

Dalam kasus Java 7, karena ketiga kelas, yaitu Socket, PrintWriter, BufferedReader, terapkan AutoCloseable dan berdasarkan fakta, Anda ingin menutup soket segera setelah Anda memanggil sendContentOverSocket(String content) coba gunakan kode berikut:

    public class SocketClient {

    private String hostName;
    private int portNumber;

    public void init(String hostName, int portNumber) {
        this.hostName = hostName;
        this.portNumber = portNumber;
    }

    public void sendContentOverSocket(String content) {
        try (Socket socket = new Socket(this.hostName, this.portNumber);
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true); 
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
            out.print(content);
        } catch(IOException e) {
            //Appropriate exception handler
        }
    }
}

Dalam hal ini Java akan menutup semua sumber daya dengan sendirinya.

Jika Anda menggunakan Java 6 atau versi lebih lama, coba gunakan coba-akhirnya blok sebagai gantinya:

person fenske    schedule 23.03.2015

terselesaikan.

saya sekarang mengerti cara kerjanya. apa yang saya lewatkan di klien adalah upaya membaca dari input Stream. Ketika Anda mencoba membaca

while ((inputFromServer = in.readLine()) != null)

klien menunggu masukan. Satu-satunya hal yang akan memutus loop ini adalah server menutup koneksi.

setelah itu terjadi Anda dapat menutup koneksi dengan aman di sisi klien. Tidak perlu menunda FIN dan semacamnya...

person mosh    schedule 24.03.2015