Socket.io: Koneksi ganda

Dibuat pada 23 Agu 2011  ·  42Komentar  ·  Sumber: socketio/socket.io

entah bagaimana koneksi ganda terjadi pada klien (artinya semua penangan dipanggil dua kali), tidak dapat mereproduksi situasi sendiri, tetapi tetap menerima laporan bug, perilakunya persis sama jika Anda memanggil socket.socket.connect () pada sudah terhubung socket. (diuji di websocket dan flashsocket)

Socket.IO client bug

Komentar yang paling membantu

Saya masih mengalami masalah ini sesuai dengan contoh dasar berikut.

EDIT: Saya menemukan perbaikan, meskipun saya tidak yakin itu tepat. Pada dasarnya semua yang dibutuhkan adalah menggunakan

io.once('connection', ...)

dari pada

io.on('connection', ...)

Semua 42 komentar

sebagai quick hack Anda dapat menggunakan "force new connection": konfigurasi palsu

Saya juga mengamati bug ini di aplikasi kami.
Reproduksi berikutnya. Di FF dengan koneksi websocket, terjadi beberapa error. Kemudian satu demi 3 peristiwa menghubungkan kembali telah dihasilkan. Setelah 3 koneksi baru ini dibuat, dan browser menerima 3 pesan, bukan satu.

Mungkin beberapa bug dalam logika koneksi ulang? Sesuatu, yang menghasilkan beberapa koneksi ulang, bukan satu.

Saya telah melihat masalah di browser lama yang tidak mendukung websockets (misalnya, FF 3.6) di mana menginisialisasi socket.io dalam acara dom ready ("$ ()" di jQuery) menyebabkan banyak koneksi saat menginisialisasi di window.load nanti acara tidak. Saya menemukan masalah khusus ini dapat direkonstruksi secara konsisten. Tidak yakin apakah itu hal yang sama yang Anda lihat tetapi gejalanya terlihat sangat mirip.

Masalah yang sama di sini juga. Masalahnya adalah jika server macet karena alasan apa pun dan kemudian dihidupkan kembali, koneksi ulang menghasilkan n + 1 tanggapan setiap saat. jadi jika kami mengatakan 3 server crash, kami memiliki 4 respons yang masuk pada setiap server yang dikeluarkan. Menyegarkan halaman menyelesaikan masalah. Adakah yang menemukan solusi untuk ini [walaupun hanya sementara?]

Ini mungkin bukan solusi permanen, tetapi saya mengatur ulang kode saya sehingga setiap acara terikat secara independen dan masalah duplikasi tampaknya telah diselesaikan pada sambungan ulang otomatis

me.socket.on('connect', function () {
});

me.socket.on('message', function(data) {

});

me.socket.on('disconnect', function() {

});

Setelah seminggu melakukan debug melalui dump Wireshark yang ditangkap, saya berhasil menemukan alasannya dan mereproduksi bug ini.

Singkatnya, logika rekoneksi sangat rapuh. Itu tergantung pada banyak timer yang dapat berjalan secara paralel dan mengarah ke beberapa koneksi ulang. Baris ini https://github.com/LearnBoost/socket.io-client/blob/master/lib/socket.js#L511 adalah alasan utama bug ini.

Sekarang reproduksi penuh:

  1. Terhubung dengan klien ke server.
  2. Masukkan kode lambat ke server Anda (kita harus menangguhkan mainloop node.js selama 4-8 detik) melalui faktorial:
    function fibo (n) {
    if (n <2) return 1;
    kembali fibo (n-2) + fibo (n-1);
    }
    Masukkan ke bagian auth. Ini harus disebut jabat tangan:
    io.set ('authorization', function (data, accept) {
    console.info ("Fibo ::" + fibo (41));
    Anda harus bereksperimen di konsol node Anda, untuk menemukan fibo (N), yang
    akan memblokir main-loop selama 4-8 detik.
  3. Sekarang, Anda harus melakukan restart cepat pada server Anda.
    Kode lambat akan berlaku untuk koneksi.
    Klien harus diberitahu bahwa ini tidak berjabat tangan.
    Dan sekarang mencoba menyambung kembali.
    Di konsol, Anda akan melihat beberapa upaya menyambungkan kembali (jika Anda mengaktifkan log in callback "sambungkan kembali / sambungkan kembali").
    Setelah peretasan perlambatan kami, itu akan diulang selamanya.

Dalam kehidupan nyata, ini direproduksi melalui pelambatan balasan server setidaknya selama beberapa detik.
Ini bisa terjadi ketika node.js berada di bawah beban berat dan merespons dengan beberapa penundaan.
Atau beberapa pelambatan jaringan juga dapat menyebabkan perilaku seperti itu.
Itu juga dapat direproduksi setelah server restart.

Baris ini (socket.js, 511):
self.reconnectionTimer = setTimeout (maybeReconnect, self.reconnectionDelay);

menjadwalkan acara setelah panggilan terhubung. Dan jika respons-koneksi tertunda setidaknya selama satu detik, itu dipicu dan memasukkan koneksi ulang baru ke dalam antrian. Setelah 2 detik itu menambahkan satu sama lain dan satu lagi.

Saya telah memperbaikinya, tetapi belum diuji dan terlihat tidak terlalu solid. Masalah utama - bagaimana alasan callback / timer mana yang dapat dijalankan secara bersamaan ke fungsi maybeReconnect.
Baris ini: https://github.com/LearnBoost/socket.io-client/blob/master/lib/socket.js#L490 juga dapat menyebabkan duplikasi koneksi.

Klien Socket.io bisa jauh lebih sederhana untuk dipikirkan, jika akan direfraktor untuk menggunakan beberapa Mesin Negara. Status saat ini tersebar di berbagai flag (terhubung, terhubung, menghubungkan kembali, dll). Dan di banyak acara saya melihat penjaga seperti "if (! Self.reconnecting)" dan banyak lainnya.
Mesin status dapat menyederhanakan logika ini untuk memiliki kumpulan status dan peristiwa. Dan pengatur waktu hanya dapat digunakan untuk mengaktifkan peristiwa. Jika event ini mencapai status yang salah, state-machine bisa mengabaikan event ini dan tidak mengganggu dirinya sendiri.

Saya belum menemukan STM yang bagus untuk JS, tetapi yang ini dari Ruby dapat dengan mudah di-porting ke JS: https://github.com/geekq/workflow

Pasti +1 untuk memperbaiki masalah ini. Saya telah berusaha mencari solusi untuk masalah ini tanpa memodifikasi socket.io atau socket.io-client secara langsung, tetapi sayangnya satu-satunya metode yang dapat saya andalkan hanyalah menonaktifkan menghubungkan kembali. Yang jelas bukan solusi yang baik, terutama dengan meningkatnya penggunaan perangkat seluler, menghubungkan kembali adalah persyaratan yang sangat besar.

Adakah yang tahu bagaimana ini termasuk dalam daftar prioritas pengembang?

Ah. Sepertinya masalah ini telah dipindahkan ke Eden ke-3 dari masalah: https://github.com/LearnBoost/socket.io/issues/430

Saya telah melakukan perbaikan untuk klien dan mengirim permintaan penarikan. Ini berfungsi dengan baik di 0.8.4 dan dapat berfungsi dengan baik di versi lain. Tapi itu membutuhkan untuk menonaktifkan kemampuan sumber untuk menggunakan AJAX (atau CORS) untuk jabat tangan. Lihat ini: https://github.com/LearnBoost/socket.io-client/pull/342 untuk detailnya.

Maaf telah menghidupkan kembali masalah lama seperti itu. Saya menggunakan saya percaya versi terbaru dari socket.io (atau setidaknya, saya melakukan npm install socket.io). Masalah ini masih terjadi pada saya, saya relatif baru mengenal socket.io dan node.js secara keseluruhan. Saya juga mengalami masalah di mana terkadang koneksi pertama (dari dua yang hanya terjadi pada satu waktu) mengalami kesalahan baca. Jika saya benar dalam mengatakan cris, perbaikan Anda telah dilakukan sehingga seharusnya tidak terjadi lagi tetapi tetap terjadi kecuali saya melewatkan faktor penting?

Edit -

Tampaknya socket.io bercabang cris dan membuat perbaikan itu dan perbaikan tidak dilakukan ke socket.io asli?

@JTallis Saya memiliki masalah yang sama dengan @gdiz dan sarannya bekerja dengan baik. Jika masalah Anda serupa, saya sarankan Anda mencobanya dan beri tahu kami cara kerjanya.

Saya juga mengalami masalah ini dengan 0.9.16 yang saya yakini sebagai versi terbaru. Bagaimana cara kerja gdiz mencegah hal ini terjadi? Tidak sepenuhnya memahaminya.

Ya ampun ... saya menghabiskan beberapa jam untuk mencari tahu apa yang salah dengan aplikasi saya, dan mengapa pesan antara server dan klien digandakan secara massal setelah koneksi terputus dan diperbarui ...

menggunakan 0.9.16 saya dapat mengkonfirmasi masalah ini

Saya bisa mendapatkan acara koneksi ganda sesuka hati dengan kode klien dan server berikut di file node.js file yang sama:

"use strict";
var server = require('socket.io');
var client = require('socket.io-client');

setTimeout(function () {
    var io = server.listen(8888);

    io.of('/chat').on('connection', function (socket) {
        console.log('Server: /chat connection');
    });

    io.sockets.on('connection', function (socket) {
        console.log('Server: connection');
    });
}, 2000);

var socketAddress = 'http://localhost:8888/chat';
var socket = client.connect(socketAddress);

socket.on('connect', function () {
    console.log("Client: connect");
});

socket.on('error', function () {
    console.log("Client: error");
    socket.socket.reconnect();
});

Beberapa hal aneh:

1) Jika saya mengubah koneksi namespaced ke yang normal dengan menghapus "/ chat" dari url maka hanya ada satu acara koneksi.

2) Jika saya memulai server segera, ubah waktu setInterval ke nol, tidak ada kesalahan koneksi awal dan hanya satu peristiwa koneksi.

Ada solusi atau perbaikan untuk ini?

Mengalami masalah yang sama. Jika server socket.io restart tiba-tiba klien menyambung kembali dua kali sehingga setiap pesan kemudian diproses dua kali oleh klien. Benar-benar mengacaukan hitungan saya di sisi klien.

Saya memiliki masalah yang sama dengan rilis 1.0.0-pre2. Saya memiliki dua "400 Bad Request" ketika saya mengembalikan socket.io.

Akan memeriksa hari ini!

Akan memeriksa hari ini!

Jangan ragu jika Anda membutuhkan lebih banyak detail, log atau layar! Tidak setiap saat.

di client socket.io.js pada 1.0.6 pada baris 2755:

Request.prototype.create = function (isBinary, supportingBinary) {
var xhr = this.xhr = new XMLHttpRequest ({agent: this.agent, xdomain: this.xd});
...
}

Saya yakin ini adalah ide yang bagus untuk mengatur:
xhr.timeout = turunan dari Manager._timeout - 10 ms
Dengan cara ini Anda mencegah pembuatan beberapa soket klien di sisi klien.
Di sisi server, beberapa soket akan menyebabkan batas waktu detak jantung.

Contoh socket.io dasar "Memulai" (http://socket.io/get-started/chat/) memiliki masalah koneksi soket ganda ini.

Salah satu dari berikut ini (dalam urutan probabilitas yang meningkat) menghasilkan koneksi soket ganda dari koneksi tab browser tunggal:
a) Saat terhubung ke localhost: 3000, dari tab browser pertama itu sendiri
b) Saat terhubung ke localhost: 3000, dari tab browser kedua
c) Menjaga konsol browser tetap terbuka, sebelum menghubungkan ke (localhost: 3000)

Pengamatan tambahan:

 io.on('connection', function(socket){
    console.log('a user connected: ' + socket.id);
    socket.on('disconnect', function(){
       console.log('a user disconnected');
       console.log(socket.nickname + ' has disconnected from the chat.');
    });
});
  1. Ada dua, socket.id berasal dari satu permintaan tab browser.
  2. Sambungan soket "duplikat" terputus sendiri, kira-kira dalam satu menit dengan console.log dari "tidak ditentukan telah terputus dari obrolan."
  3. Menggunakan generator cepat 4.2 (menggunakan Morgan) dan kemudian menerapkan contoh "Memulai", koneksi browser yang "baik" menghasilkan log ekspres dari satu baris, misalnya "GET / 304 1ms". Tetapi setiap kali, ada koneksi soket "ganda", ada dua log ekspres, "GET / 304 1ms" DAN "GET / 200 3ms - 386b"

Saya menggunakan Mac, Chrome, Express 4.2 dan socket.io terbaru.

Ada perbedaan waktu antara pembuatan kedua log. Log pertama diaktifkan saat Chrome melengkapi otomatis "lo" saya ke " localhost: 3000 " dan log kedua diaktifkan saat saya menekan tombol enter.

Saya mendapat pesan log konsol "Pengguna X terhubung" dan sangat mengganggu saat browser saya memicu 2 atau 3 pemberitahuan koneksi pengguna.

Sekarang, saya harus mengakui bahwa solusi saya untuk masalah ini adalah mengomentari baris console.log. Tapi pertahankan kerja bagus, guys.

Saya masih melihat masalah ini di versi terbaru. Ada pembaruan tentang ini?

Saya melihat masalah ini dengan 1.0 juga

Tidak bisa mereproduksi sama sekali. Bisakah seseorang memposting contoh lengkap?

Pada Jum 14 November 2014 pukul 2:44:50 Rex Pechler [email protected]
menulis:

Saya melihat masalah ini dengan 1.0 juga

-
Balas email ini secara langsung atau lihat di GitHub
https://github.com/Automattic/socket.io/issues/474#issuecomment -62934229
.

Saya akan melihat apakah saya bisa memberikan contoh sederhana besok.

Saya mungkin mereproduksinya. Saya menggunakan socket.io 1.3.5 dan express 4.12.4.

Aplikasi ekspres saya berada di 127.0.0.1:3000 dan saya membuka browser saya dan mengetikkan alamat ip dan socket.io itu hanya membuka satu websocket.

Saya memiliki domain seperti abc.com dan saya meneruskannya ke 127.0.0.1. Saya membuka abc.com di browser saya dan di file index.html ada baris;

<script>
        var socket = io('http://localhost:3000/mysql');

        socket.on('processlist', function (data){
            console.log(data);
        });
</script>

ini membuka 2 websockets.

Saya belum mencoba nginx dengan proxy. Saya akan memberi tahu Anda segera setelah saya mencoba.

screen shot 2015-05-29 at 23 53 29

Masih mengalami masalah ini. Bagi saya itu terjadi pada restart server - Saya melampirkan penangan kejadian socket.on ('message') saya ketika peristiwa koneksi awal dari server dipicu, dan jika server dimulai ulang saat klien terbuka, peristiwa itu dipecat beberapa kali (lebih banyak waktu lagi klien telah menunggu server restart).

Perbaikan saya untuk saat ini adalah untuk 'melepaskan' acara soket yang dilampirkan sehingga hanya terjadi pada server pertama yang terhubung, seperti:

client.socketEventsAttached = false;

socket.on('connect',function(){
     if (!client.socketEventsAttached){
          attachSocketEvents();
     }
});

Anda juga dapat meletakkan listener event pesan Anda di luar listener socket.on ('connect') seperti yang disarankan @gdiz . Saya baru saja mengalami beberapa masalah di sana dengan peristiwa soket yang diaktifkan sebelum server atau klien siap untuk mereka.

@bbcollinsworth apa objek klien?

Masih menghadapi masalah ini dengan socketio baru dan contoh dasar.

Saya masih mengalami masalah ini sesuai dengan contoh dasar berikut.

EDIT: Saya menemukan perbaikan, meskipun saya tidak yakin itu tepat. Pada dasarnya semua yang dibutuhkan adalah menggunakan

io.once('connection', ...)

dari pada

io.on('connection', ...)

@brandonraphael dapatkah Anda memberikan contoh yang mereproduksi masalah Anda (berdasarkan https://github.com/darrachequesne/socket.io-fiddle misalnya) dan membuka masalah baru?

Pembaruan apa pun ini masih terjadi dan menciptakan masalah di aplikasi

Ini adalah log -
0 | Server Api | Terhubung !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DKap3hUYFSpKBRr7AFgc 4351 2018-12-26 10:58:25
0 | Server Api | Terhubung !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! VS98DBFVTNF6ifzmAFgd 4351 2018-12-26 10:58:25

4351 adalah user id dan jumlah koneksinya juga tidak statis seperti 2 pada kasus user 4351.
Log lain menunjukkan 6 koneksi pada waktu yang sama untuk pengguna yang sama.

Juga, periksa kedua id soket ini di server dan mereka menunjukkan valid. Tetapi frontend hanya dapat mendengarkan salah satunya yang selalu merupakan id soket pertama.

Bantuan apa pun akan sangat bagus.
Terima kasih sebelumnya.

Saya masih mengalami masalah ini sesuai dengan contoh dasar berikut.

EDIT: Saya menemukan perbaikan, meskipun saya tidak yakin itu tepat. Pada dasarnya semua yang dibutuhkan adalah menggunakan

io.once('connection', ...)

dari pada

io.on('connection', ...)

Terima kasih untuk ini

Masalah teratasi setelah mengubah versi yang digunakan di sisi klien. Perbaikan lain akan menggunakan kamar, bukan id soket tunggal. Menemukan bahwa setiap id soket itu sendiri adalah satu-satunya bagian ruangan yang akan diubah adalah kode koneksi baru untuk meletakkan setiap id soket di ruang pengguna.
Pertimbangkan siput pengguna adalah Pengguna1 kemudian ruang dibuat Pengguna1 dan setiap koneksi soket baru melalui siput Pengguna1 dimasukkan ke dalam ruang Pengguna1.

Mengalami masalah yang sama dan itu membuat saya gila. Jelas TIDAK mendaftarkan ulang pendengar acara di klien juga. Dalam pengaturan saya, saya memiliki server nodejs yang menghosting titik akhir socketio dan saya juga memiliki server nodejs lain yang bertindak sebagai klien socketio saya. Triknya adalah menghubungkan sisi klien dengan transport websocket dan menggunakan forceNode . Ex

// client side
const socket = io('<url>', {
  transports: ['websocket'],
  forceNode: true,
});

Saya yakin saya mengalami masalah yang sama. Saya sedang membangun ruang obrolan dan ketika seseorang bergabung dengan ruang itu, saya memancarkan "telah bergabung dengan pesan ruang "ke ruang.

Semuanya berfungsi dengan baik, tetapi jika saya meninggalkan ruangan dan kemudian memasukinya untuk kedua kalinya, pesan intro dipancarkan _twice_. Jika saya meninggalkan ruangan lagi dan masuk kembali untuk ketiga kalinya, pesan intro dibunyikan tiga kali, dan seterusnya. Setiap _reconnection_ ke ruang _same_ menghasilkan duplikat pesan intro. Namun, jika saya memasuki ruang _different_, saya hanya melihat pesan intro sekali.

Menggunakan io.once('connection', ...) tidak berhasil untuk saya. Faktanya, semua acara saya berhenti bekerja.

Menggunakan metode "debounce" juga tidak berhasil. Sekali lagi, tidak ada acara saya yang terdaftar.

Terakhir, menggunakan sisi klien opsi forceNode: true juga tidak berfungsi.

Saya menggunakan 2.2.0 pada server dan klien. Apakah ada yang saya lewatkan?

Saya bertanya-tanya tentang masalah yang sama, tetapi pada akhirnya, memberi tahu klien untuk menghubungkan hanya once membantu.

Inilah konfigurasi saya untuk klien:

var socket = io.connect("http://localhost:3000/test", 
    { upgrade: false, transports: ['websocket'], reconnection: true, forceNew: false});
socket.once('connect', socketConn => {
    socket.on('message', data => {
        console.log(data);
    });
}); 

Klien hanya akan didaftarkan once untuk connect acara, sehingga acara lain di dalamnya akan didaftarkan sekali. Sekarang jika server akan macet, klien hanya akan mencoba menyambung kembali dan tidak akan mencoba membuat koneksi baru. Segera setelah mendapat respon dari server, itu akan mulai memproses pesan.

Jadi io.once perlu disetel di sisi klien, bukan di sisi server.

Saya menggunakan klien versi 2.1. Saya merasa sangat mudah memicunya di dev env saya. Setiap kali server node saya restart (misalnya menggunakan nodemon) klien selalu memicu beberapa acara menghubungkan kembali kemudian menghubungkan genap. Tapi saya tidak bisa menemukan akar penyebabnya

Saya menggunakan klien versi 2.1. Saya merasa sangat mudah memicunya di dev env saya. Setiap kali server node saya restart (misalnya menggunakan nodemon) klien selalu memicu beberapa acara menghubungkan kembali kemudian menghubungkan genap. Tapi saya tidak bisa menemukan akar penyebabnya

Saya mengalami masalah yang sama dengan menggunakan nodemon itu sendiri. tetapi pada akhirnya, memberi tahu klien untuk menghubungkan hanya once membantu.
Coba kode dari balasan saya tepat di atas. Ini membantu saya dan setiap kali server dimulai ulang, klien mendapatkan koneksi baru.

Masalah saya sederhana

Saya membuka aplikasi sisi klien yang sama di 2 tab. Ups

Saya juga memiliki masalah yang sama. Namun, bagi saya, saya salah menempatkan penangan sisi klien saya di dalam fungsi callback socket.on('connection', cb) .

Berikut cuplikan untuk ditunjukkan:

client.js (di node.js)

const client = require('socket.io-client');
const socket = client('my_endpoint', {
  transports: [ 'websockets' ]
});

socket.on('connect', () => {
  console.log('connected');
  socket.on('myEvent', (message) => {
    console.log(`message: ${message}`);
  });
});

Ketika pemutusan dan penyambungan kembali terjadi, itu akan memanggil socket.on('connect', cb) lagi, dan penangan myEvent akan mendaftarkan penangan kedua dengan nama yang sama. Jadi, ketika server mengeluarkan myEvent lagi, saya akan memiliki dua log konsol dari pesan yang sama.

Untuk mengatasinya, saya harus menempatkan penangan saya yang lain di luar penangan connect .

const client = require('socket.io-client');
const socket = client('my_endpoint', {
  transports: [ 'websockets' ]
});

socket.on('connect', () => {
  console.log('connected');
});

socket.on('myEvent', (message) => {
  console.log(`message: ${message}`);
});

Saya pikir kebingungan saya datang dari bagaimana dokumen menunjukkan sisi server menempatkan socket.on peristiwa di dalam acara connect . Itu untuk saya karena tidak membaca dokumen dengan lebih cermat, tetapi saya pikir saya akan meletakkan ini di sini jika ada orang lain yang membuat kesalahan yang sama.

Juga, meskipun saya melihat masalah ini secara khusus di node.js, saya yakin ini juga akan menjadi masalah di browser.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat