Kirim pesan ke klien tertentu dengan socket.io dan node.js

191

Saya bekerja dengan socket.io dan node.js dan sampai sekarang sepertinya cukup bagus, tetapi saya tidak tahu bagaimana mengirim pesan dari server ke klien tertentu, sesuatu seperti ini:

client.send(message, receiverSessionId)

Tetapi baik metode .send()maupun .broadcast()metode tampaknya tidak memenuhi kebutuhan saya.

Apa yang saya temukan sebagai solusi yang mungkin, adalah bahwa .broadcast()metode menerima sebagai parameter kedua array SessionIds yang tidak mengirim pesan, jadi saya bisa meneruskan array dengan semua SessionIds yang terhubung pada saat itu ke server, kecuali yang Saya ingin mengirim pesan, tetapi saya merasa harus ada solusi yang lebih baik.

Ada ide?

Rodolfo Palma
sumber

Jawaban:

95

Nah Anda harus meraih klien untuk itu (kejutan), Anda bisa pergi dengan cara sederhana:

var io = io.listen(server);
io.clients[sessionID].send()

Yang mungkin pecah, saya ragu, tapi selalu ada kemungkinan yang io.clientsbisa berubah, jadi gunakan yang di atas dengan hati-hati

Atau Anda melacak klien sendiri, karena itu Anda menambahkannya ke objek Anda sendiri clientsdi connectionpendengar dan menghapusnya di disconnectpendengar.

Saya akan menggunakan yang terakhir, karena tergantung pada aplikasi Anda, Anda mungkin ingin memiliki lebih banyak negara pada klien, jadi sesuatu seperti clients[id] = {conn: clientConnect, data: {...}}mungkin melakukan pekerjaan.

Ivo Wetzel
sumber
6
Ivo, dapatkah Anda menunjukkan contoh yang lebih lengkap atau sedikit rumit? Saya ingin memahami pendekatan ini, tetapi saya tidak yakin saya mengenali variabel / objek yang Anda gunakan dalam contoh ini. Di klien [id] = {conn: clientConnect, data: {...}}, apakah klien [id] bagian dari objek io seperti yang terlihat di io.clients [sessionID] di atas? Juga apa objek clientConnect? Terima kasih.
AndrewHenderson
@ ivo-wetzel hai, bisakah kamu menyapa saya tentang topik ini? stackoverflow.com/questions/38817680/…
mahdi pishguy
178

Jawaban Ivo Wetzel sepertinya tidak berlaku lagi di Socket.io 0.9 lagi.

Singkatnya, Anda sekarang harus menyimpan socket.iddan menggunakannya io.sockets.socket(savedSocketId).emit(...) untuk mengirim pesan kepadanya.

Ini adalah bagaimana saya membuatnya bekerja di server Node.js yang dikelompokkan:

Pertama, Anda perlu mengatur toko Redis sebagai toko sehingga pesan dapat melewati proses:

var express = require("express");
var redis = require("redis");
var sio = require("socket.io");

var client = redis.createClient()
var app = express.createServer();
var io = sio.listen(app);

io.set("store", new sio.RedisStore);


// In this example we have one master client socket 
// that receives messages from others.

io.sockets.on('connection', function(socket) {

  // Promote this socket as master
  socket.on("I'm the master", function() {

    // Save the socket id to Redis so that all processes can access it.
    client.set("mastersocket", socket.id, function(err) {
      if (err) throw err;
      console.log("Master socket is now" + socket.id);
    });
  });

  socket.on("message to master", function(msg) {

    // Fetch the socket id from Redis
    client.get("mastersocket", function(err, socketId) {
      if (err) throw err;
      io.sockets.socket(socketId).emit(msg);
    });
  });

});

Saya menghilangkan kode pengelompokan di sini, karena itu membuat ini lebih berantakan, tetapi sepele untuk ditambahkan. Cukup tambahkan semuanya ke kode pekerja. Lebih banyak dokumen di sini http://nodejs.org/api/cluster.html

Epeli
sumber
4
Terima kasih itu sangat membantu. Saya hanya harus menggunakan array sebagai gantinya: io.of('/mynamespace').sockets[socketID].emit(...)(tidak tahu apakah itu karena saya menggunakan namespace)
Adrien Schuler
pada lingkungan yang berkerumun, bagaimana cara memastikan bahwa proses yang benar milik soket adalah mengirim pesan?
Gal Ben-Haim
Bagaimana dengan sesi sticky milik NGINX atau HAProxy @Gal Ben-Haim?
matanster
pemegang var = socketio.RedisStore baru; ^ TypeError: undefined bukan fungsi di Object. <anonymous> (C: \ Users \ Dev \ Desktop \ nouty-server \ server.js: 108: 14) di Module._compile (module.js: 460: 26) di Object.Module._extensions..js (module.js: 478: 10) di Module.load (module.js: 355: 32) di Function.Module._load (module.js: 310: 12) di Function.Module. runMain (module.js: 501: 10) saat startup (node.js: 129: 16) di node.js: 814: 3
Lucas Bertollo
1
io.sockets.socket(socket_id)dihapus di socket.io 1.0. github.com/socketio/socket.io/issues/1618#issuecomment-46151246
ImMathan
98

setiap soket bergabung dengan sebuah ruangan dengan id soket untuk sebuah nama, jadi Anda bisa saja

io.to(socket#id).emit('hey')

docs: http://socket.io/docs/rooms-and-namespaces/#default-room

Bersulang

Matic Kogovšek
sumber
7
Ini adalah jawaban terbaik dan berfungsi dengan socket.io versi yang lebih baru. Ada lembar contekan yang bagus di sini: stackoverflow.com/questions/10058226/…
blented
4
perhatikan bahwa ini adalah jenis 'siaran' yang memancarkan suatu acara. jadi jika Anda mencoba mengatur panggilan balik ke ini, Anda akan memiliki kesalahan. jika Anda perlu mengirim acara ke soket tertentu dengan panggilan balik, kemudian gunakan jawaban dan penggunaan @ PHPthinking io.sockets.connected[socketid].emit();. Diuji dengan 1.4.6.
tbutcaru
Tetapi saya mendapatkan kesalahan ini: io.to ["JgCoFX9AiCND_ZhdAAAC"]. Emit ("socketFromServe‌ r", info); ^ TypeError: Tidak dapat membaca properti 'memancarkan' yang tidak terdefinisi
Raz
85

Solusi paling sederhana, paling elegan

Semudah:

client.emit("your message");

Dan itu saja.

Tapi bagaimana caranya? Berikan saya contoh

Apa yang kita semua butuhkan sebenarnya adalah contoh lengkap, dan itulah yang mengikuti. Ini diuji dengan versi socket.io terbaru (2.0.3) dan juga menggunakan Javascript modern (yang seharusnya kita semua gunakan sekarang).

Contohnya terdiri dari dua bagian: server dan klien. Setiap kali klien terhubung, klien mulai menerima nomor urut berkala dari server. Urutan baru dimulai untuk setiap klien baru, sehingga server harus melacaknya secara individual. Di situlah "Saya perlu mengirim pesan ke klien tertentu" mulai berperan. Kode ini sangat sederhana untuk dipahami. Mari kita lihat.

Server

server.js

const
    io = require("socket.io"),
    server = io.listen(8000);

let
    sequenceNumberByClient = new Map();

// event fired every time a new client connects:
server.on("connection", (socket) => {
    console.info(`Client connected [id=${socket.id}]`);
    // initialize this client's sequence number
    sequenceNumberByClient.set(socket, 1);

    // when socket disconnects, remove it from the list:
    socket.on("disconnect", () => {
        sequenceNumberByClient.delete(socket);
        console.info(`Client gone [id=${socket.id}]`);
    });
});

// sends each client its current sequence number
setInterval(() => {
    for (const [client, sequenceNumber] of sequenceNumberByClient.entries()) {
        client.emit("seq-num", sequenceNumber);
        sequenceNumberByClient.set(client, sequenceNumber + 1);
    }
}, 1000);

Server mulai mendengarkan pada port 8000 untuk koneksi masuk. Ketika seseorang tiba, ia menambahkan klien baru itu ke peta sehingga ia dapat melacak nomor urutnya. Itu juga mendengarkan disconnectacara klien itu , ketika itu akan menghapusnya dari peta.

Setiap detik, penghitung waktu diaktifkan. Ketika itu terjadi, server berjalan melalui peta dan mengirim pesan ke setiap klien dengan nomor urut saat ini. Itu kemudian bertambah dan menyimpan nomor kembali di peta. Itu semua untuk itu. Peasy mudah.

Klien

Bagian klien bahkan lebih sederhana. Itu hanya terhubung ke server dan mendengarkan seq-numpesan, mencetaknya ke konsol setiap kali itu tiba.

client.js

const
    io = require("socket.io-client"),
    ioClient = io.connect("http://localhost:8000");

ioClient.on("seq-num", (msg) => console.info(msg));

Menjalankan contoh

Instal perpustakaan yang diperlukan:

npm install socket.io
npm install socket.io-client

Jalankan server:

node server

Buka jendela terminal lain dan berikan klien sebanyak yang Anda inginkan dengan menjalankan:

node client

Saya juga sudah menyiapkan inti dengan kode lengkap di sini .

Lucio Paiva
sumber
Apakah port 8000 norma untuk socketio dalam produksi?
Merah
1
Maaf saya butuh waktu lama untuk membalas, @ingo. 8000 adalah port umum yang digunakan oleh komunitas Node saat menguji kedua websockets atau server HTTP (3000 juga umum). Tentu saja Anda bisa menggunakannya dalam produksi, tapi saya tidak yakin seberapa umum itu ... tetap, Anda bisa menggunakan port apa saja, asalkan gateway / load balancers / etc siap untuk itu.
Lucio Paiva
Saya programmer Python / PHP dan saya baru ke soket dan simpul, pertanyaannya adalah, mengapa kita perlu menambah jumlah seq pengguna yang sama setiap detik? apakah itu hanya untuk demo?
Umair
1
@Umair itu hanya untuk keperluan demo, tidak perlu menambah nomor urut. Itu hanya untuk menunjukkan bahwa Anda dapat terus mengirim barang ke setiap klien dan mereka akan menerimanya.
Lucio Paiva
Saya tidak melihat dalam contoh ini bagaimana klien tertentu hanya mengirim pesan dan hanya ke klien lain. Setiap klien hanya mengetahui nomor urut mereka sendiri seperti yang Anda beri nama dan membuatnya untuk demo, dan tidak ada peta dari nomor urut ini ke id soket yang diperlukan untuk mengirim pesan langsung ke klien dengan id soket itu.
Selçuk
36

Kamu bisa memakai

// kirim pesan hanya ke klien-pengirim

socket.emit('message', 'check this');

// atau Anda dapat mengirim ke semua pendengar termasuk pengirim

io.emit('message', 'check this');

// kirim ke semua pendengar kecuali pengirim

socket.broadcast.emit('message', 'this is a message');

// atau Anda dapat mengirimnya ke kamar

socket.broadcast.to('chatroom').emit('message', 'this is the message to all');

DekoderNT
sumber
Bekerja untuk saya, saya juga harus menambahkan "const socket = require ('socket.io') (http);" dalam file server.js saya.
iPzard
36

Di 1.0 Anda harus menggunakan:

io.sockets.connected[socketid].emit();
Pemikiran PHP
sumber
1
Ya !!!, sebelumnya io.sockets.sockets [socketid] .emit () berfungsi, tetapi ini memberi saya kesalahan objek yang tidak terdefinisi di versi socket.io yang lebih baru. Mengubah ke karya-karya io.sockets.connected.
Fraggle
Bagi mereka yang menggunakan TypeScript, saat ini API 'kanonik' untuk ini sesuai dengan pengetikan.
Avi Cherry
Tetapi saya menerima kesalahan: io.sockets.connected ["JgCoFX9AiCND_ZhdAAAC"]. Emit ("socketFromServer", info); ^ TypeError: Tidak dapat membaca properti 'memancarkan' tidak terdefinisi
Raz
itu mungkin karena fakta bahwa api diperbarui dan tidak ada lagi objek seperti io.sockets.connected["something"]dan emitmetodenya.
Selçuk
12

Versi apa pun yang kami gunakan jika kami hanya console.log () objek "io" yang kami gunakan dalam kode nodejs sisi server kami, [mis. Io.on ('koneksi', fungsi (soket) {...});] , kita dapat melihat bahwa "io" hanyalah objek json dan ada banyak objek anak di mana id socket dan objek socket disimpan.

Saya menggunakan socket.io versi 1.3.5, btw.

Jika kita melihat pada objek io, itu berisi,

 sockets:
  { name: '/',
    server: [Circular],
    sockets: [ [Object], [Object] ],
    connected:
     { B5AC9w0sYmOGWe4fAAAA: [Object],
       'hWzf97fmU-TIwwzWAAAB': [Object] },

di sini kita dapat melihat socketid "B5AC9w0sYmOGWe4fAAAA" dll. Jadi, kita bisa melakukan,

io.sockets.connected[socketid].emit();

Sekali lagi, pada pemeriksaan lebih lanjut kita dapat melihat segmen seperti,

 eio:
  { clients:
     { B5AC9w0sYmOGWe4fAAAA: [Object],
       'hWzf97fmU-TIwwzWAAAB': [Object] },

Jadi, kita dapat mengambil soket dari sini dengan melakukan

io.eio.clients[socketid].emit();

Juga, di bawah mesin yang kami miliki,

engine:
 { clients:
    { B5AC9w0sYmOGWe4fAAAA: [Object],
      'hWzf97fmU-TIwwzWAAAB': [Object] },

Jadi, kita juga bisa menulis,

io.engine.clients[socketid].emit();

Jadi, saya kira kita dapat mencapai tujuan kita dengan salah satu dari 3 cara yang saya sebutkan di atas,

  1. io.sockets.connected [socketid] .emit (); ATAU
  2. io.eio.clients [socketid] .emit (); ATAU
  3. io.engine.clients [socketid] .emit ();
Suman Barick
sumber
Tetapi saya mendapatkan kesalahan ini: io.eio.clients ["JgCoFX9AiCND_ZhdAAAC"]. Emit ("socketFromServer", info); ^ TypeError: Tidak dapat membaca properti 'memancarkan' yang tidak terdefinisi
Raz
Saat ini (dengan versi 2.1.1) ini hanya berfungsi untuk sockets.connected, tetapi tidak untuk dua lainnya.
James
10

Kamu bisa melakukan ini

Di server.

global.io=require("socket.io")(server);

io.on("connection",function(client){
    console.log("client is ",client.id);
    //This is handle by current connected client 
    client.emit('messages',{hello:'world'})
    //This is handle by every client
    io.sockets.emit("data",{data:"This is handle by every client"})
    app1.saveSession(client.id)

    client.on("disconnect",function(){
        app1.deleteSession(client.id)
        console.log("client disconnected",client.id);
    })

})

    //And this is handle by particular client 
    var socketId=req.query.id
    if(io.sockets.connected[socketId]!=null) {
        io.sockets.connected[socketId].emit('particular User', {data: "Event response by particular user "});
    }

Dan pada klien, sangat mudah untuk ditangani.

var socket=io.connect("http://localhost:8080/")
    socket.on("messages",function(data){
        console.log("message is ",data);
        //alert(data)
    })
    socket.on("data",function(data){
        console.log("data is ",data);
        //alert(data)
    })

    socket.on("particular User",function(data){
        console.log("data from server ",data);
        //alert(data)
    })
abhaygarg12493
sumber
7

Pada versi 1.4.5, pastikan Anda memberikan socketId yang diawali dengan benar di io.to (). Saya mengambil socketId Klien login ke debug dan itu tanpa awalan jadi saya akhirnya mencari selamanya sampai saya tahu! Jadi, Anda mungkin harus melakukannya seperti ini jika ID yang Anda miliki tidak diawali:

io.to('/#' + socketId).emit('myevent', {foo: 'bar'});
risuch
sumber
6

io.sockets.sockets [socket.id] .emit (...) bekerja untuk saya di v0.9

aljosa
sumber
Selamat datang di Stack Overflow. Jawaban ini tampaknya tidak menambah banyak kaitan dengan jawaban yang ada. Setelah memiliki lebih banyak reputasi , Anda dapat mengomentari pos orang lain . Ini sepertinya lebih cocok untuk komentar.
jerry
2

Anda juga dapat menyimpan referensi klien. Tetapi ini membuat kenangan Anda sibuk.

Buat objek kosong dan setel klien Anda ke dalamnya.

const myClientList = {};

  server.on("connection", (socket) => {
    console.info(`Client connected [id=${socket.id}]`);
     myClientList[socket.id] = socket;   
  });
  socket.on("disconnect", (socket) => {
    delete myClientList[socket.id];
  });

kemudian panggil klien spesifik Anda dengan id dari objek

myClientList[specificId].emit("blabla","somedata");
Kamuran Sönecek
sumber
0

Socket.IO memungkinkan Anda untuk "namespace" soket Anda, yang pada dasarnya berarti menetapkan titik akhir atau jalur yang berbeda.

Ini mungkin membantu: http://socket.io/docs/rooms-and-namespaces/

Igor T.
sumber