सॉकेट.आईओ और नोड.जेएस के साथ विशिष्ट ग्राहक को संदेश भेजें


190

मैं सॉकेट.आईओ और नोड.जेएस के साथ काम कर रहा हूं और अब तक यह काफी अच्छा लग रहा है, लेकिन मुझे नहीं पता कि सर्वर से किसी विशिष्ट क्लाइंट को संदेश कैसे भेजा जाए, कुछ इस तरह:

client.send(message, receiverSessionId)

लेकिन न तो .send()है और न ही .broadcast()तरीकों मेरी जरूरत की आपूर्ति करने लगते हैं।

मैंने एक संभावित समाधान के रूप में जो पाया है, वह यह है कि यह .broadcast()विधि एक दूसरे पैरामीटर के रूप में स्वीकार कर लेती है, जो संदेश भेजने के लिए नहीं है, इसलिए मैं उस क्षण से जुड़े सभी सत्रों के साथ एक सरणी को सर्वर के पास भेज सकता हूं, केवल एक को छोड़कर मैं संदेश भेजना चाहता हूं, लेकिन मुझे लगता है कि बेहतर समाधान होना चाहिए।

कोई विचार?

जवाबों:


95

वैसे आपको ग्राहक को उस (आश्चर्य) के लिए पकड़ना होगा, आप या तो सरल तरीके से जा सकते हैं:

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

जो टूट सकता है, मुझे संदेह है, लेकिन यह हमेशा एक संभावना है जो io.clientsबदल सकती है, इसलिए सावधानी के साथ उपरोक्त का उपयोग करें

या आप स्वयं क्लाइंट्स पर नज़र रखते हैं, इसलिए आप उन्हें श्रोता clientsमें अपनी वस्तु में जोड़ते हैं connectionऔर उन्हें disconnectश्रोता में हटा देते हैं।

मैं बाद वाले का उपयोग करूँगा, क्योंकि आपके आवेदन के आधार पर आप ग्राहकों पर और अधिक राज्य करना चाह सकते हैं, इसलिए कुछ clients[id] = {conn: clientConnect, data: {...}}ऐसा काम कर सकते हैं।


6
इवो, क्या आप अधिक पूर्ण उदाहरण की ओर इशारा कर सकते हैं या थोड़ा विस्तार कर सकते हैं? मैं इस दृष्टिकोण को समझने के लिए उत्सुक हूं, लेकिन मुझे यकीन नहीं है कि मैं इस उदाहरण में उपयोग किए जा रहे चर / वस्तुओं को पहचानता हूं। क्लाइंट्स में [id] = {con: clientConnect, data: {...}, क्या क्लाइंट [id] io ऑब्जेक्ट का हिस्सा है, जैसा कि io.clients [sessionID] में देखा गया है? इसके अलावा क्लाइंटकनेक्ट ऑब्जेक्ट क्या है? धन्यवाद।
एंड्रयूहेंडर्सन

@ ivo- वेटज़ेल हाय, क्या आप मुझे इस विषय पर नमस्कार कर सकते हैं? stackoverflow.com/questions/38817680/…
mahdi pishguy

178

इवो ​​वेटजेल का उत्तर सॉकेट.आईओ 0.9 में अब मान्य नहीं लगता है।

संक्षेप में अब आपको इसे भेजने और इसे संदेश भेजने के लिए socket.idउपयोग io.sockets.socket(savedSocketId).emit(...)करना होगा।

इस तरह से मुझे क्लस्टर Node.js सर्वर में यह काम मिल गया है:

सबसे पहले आपको रेडिस स्टोर को स्टोर के रूप में सेट करना होगा ताकि संदेश क्रॉस प्रोसेस में जा सकें:

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);
    });
  });

});

मैंने यहां क्लस्टरिंग कोड को छोड़ दिया है, क्योंकि यह इसे अधिक अव्यवस्थित बनाता है, लेकिन इसे जोड़ने के लिए तुच्छ है। बस कार्यकर्ता कोड में सब कुछ जोड़ें। अधिक डॉक्स यहां http://nodejs.org/api/cluster.html


4
धन्यवाद यह मददगार था। मुझे इसके बजाय केवल एक सरणी का उपयोग करना था: io.of('/mynamespace').sockets[socketID].emit(...)(पता नहीं कि क्या यह इसलिए है क्योंकि मैं एक नाम स्थान का उपयोग कर रहा हूं)
एड्रियन शूलर

गुच्छेदार वातावरण पर, मैं यह कैसे सुनिश्चित करूँ कि सॉकेट जिस सही प्रक्रिया से जुड़ा हुआ है वह संदेश भेज रहा है?
गैल बेन-हैम

NGINX या HAProxy @Gal Ben-Haim के एक चिपचिपा सत्र शिष्टाचार के बारे में कैसे?
Matanster

var धारक = new socketio.RedisStore; ^ TypeError: अपरिभाषित वस्तु पर एक फ़ंक्शन नहीं है। <गुमनाम> (C: \ Users \ Dev \ Desktop \ nouty-server \ server.js: 108: 14) Module._compile (मॉड्यूल.js: 460: 26) पर Object.Module._extensions..js (मॉड्यूल.js: 478: 10) समारोह में। Module.load (मॉड्यूल.js: 355: 32) फंक्शन पर। Module._load (मॉड्यूल.js: 310: 12) फंक्शन.मॉडल पर। runMain (मॉड्यूल। जेएस: 501: 10) स्टार्टअप पर (नोड.जेएस: 129: 16) नोड पर। जेएस: 814: 3
लुकास बर्टोलो

1
io.sockets.socket(socket_id)सॉकेट में हटा दिया जाता है। 1.0। github.com/socketio/socket.io/issues/1618#issuecomment-46151246
ImMathan

97

प्रत्येक सॉकेट एक कमरे में एक नाम के लिए सॉकेट आईडी के साथ जुड़ता है, इसलिए आप बस कर सकते हैं

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

डॉक्स: http://socket.io/docs/rooms-and-namespaces/#default-room

चियर्स


7
यह सबसे अच्छा उत्तर है और socket.io के w / नए संस्करणों पर काम करता है। यहाँ एक अच्छा धोखा पत्र है: stackoverflow.com/questions/10058226/…
ब्लेंड

4
ध्यान दें कि यह किसी घटना को प्रसारित करने का एक 'प्रसारण' प्रकार है। इसलिए यदि आप इस पर कॉलबैक सेट करने का प्रयास करते हैं, तो आपको एक त्रुटि होगी। अगर आपको कॉलबैक के साथ एक विशेष सॉकेट में एक घटना भेजने की आवश्यकता है, तो @ PHPthinking का जवाब और उपयोग करें io.sockets.connected[socketid].emit();। 1.4.6 के साथ परीक्षण किया गया।
त्बुतकारू

लेकिन मुझे यह त्रुटि मिली: io.to ["JgCoFX9AiCND_ZhdAAAC"]। emit ("socketFromServeh r", जानकारी); ^ टाइपराइटर: अपरिभाषित की संपत्ति 'एमिट' नहीं पढ़ सकते हैं
आरजे

85

सबसे सरल, सबसे सुरुचिपूर्ण समाधान

यह उतना आसान है:

client.emit("your message");

और बस।

पर कैसे? मुझे एक उदाहरण दे

हम सभी की जरूरत है वास्तव में एक पूर्ण उदाहरण है, और वह इस प्रकार है। यह सबसे हाल ही में सॉकेट.आईओ संस्करण (2.0.3) के साथ परीक्षण किया गया है और यह आधुनिक जावास्क्रिप्ट का उपयोग भी कर रहा है (जो कि हमें अब तक सभी का उपयोग करना चाहिए)।

उदाहरण में दो भाग शामिल हैं: एक सर्वर और एक क्लाइंट। जब भी कोई क्लाइंट कनेक्ट होता है, तो वह सर्वर से एक आवधिक अनुक्रम संख्या प्राप्त करना शुरू कर देता है। प्रत्येक नए क्लाइंट के लिए एक नया अनुक्रम शुरू किया जाता है, इसलिए सर्वर को व्यक्तिगत रूप से उनका ट्रैक रखना पड़ता है। यही कारण है कि "मुझे एक विशेष ग्राहक को संदेश भेजने की आवश्यकता है" खेल में आता है। कोड समझने में बहुत सरल है। चलिये देखते हैं।

सर्वर

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);

आने वाले कनेक्शन के लिए सर्वर पोर्ट 8000 पर सुनना शुरू कर देता है। जब कोई आता है, तो वह उस नक्शे में नए क्लाइंट को जोड़ता है ताकि वह अपने अनुक्रम संख्या का ट्रैक रख सके। यह उस क्लाइंट के disconnectईवेंट के लिए भी सुनता है , जब वह इसे मैप से हटा देगा।

प्रत्येक और हर दूसरे, एक टाइमर निकाल दिया जाता है। जब यह होता है, तो सर्वर मानचित्र के माध्यम से चलता है और प्रत्येक ग्राहक को उसके वर्तमान अनुक्रम संख्या के साथ एक संदेश भेजता है। यह तब इसे बढ़ाता है और नक्शे में संख्या को वापस संग्रहीत करता है। बस इतना ही करना है। बहुत आसान।

ग्राहक

क्लाइंट का हिस्सा और भी सरल है। यह बस सर्वर से जुड़ता है और seq-numसंदेश के लिए सुनता है , इसे हर बार आने वाले कंसोल पर प्रिंट करता है।

client.js

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

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

उदाहरण चल रहा है

आवश्यक लाइब्रेरी स्थापित करें:

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

सर्वर चलाएँ:

node server

अन्य टर्मिनल विंडो खोलें और जितने ग्राहक चलाना चाहते हैं, चलाएं:

node client

मैंने यहां पूरे कोड के साथ एक जिस्ट भी तैयार किया है


पोर्ट 8000 उत्पादन में सॉकेटियो के लिए आदर्श है?
लाल

1
क्षमा करें, मुझे वापस उत्तर देने में इतना समय लगा, @ लिंगो। 8000 एक सामान्य पोर्ट है जिसका उपयोग नोड समुदाय द्वारा किया जाता है, जब दोनों वेबसैट या HTTP सर्वर (3000 भी सामान्य) का परीक्षण करते हैं। बेशक आप इसे उत्पादन में उपयोग कर सकते हैं, लेकिन मुझे यकीन नहीं है कि यह कितना सामान्य है ... वैसे भी, आप बस किसी भी पोर्ट का उपयोग कर सकते हैं, जब तक कि आपके गेटवे / लोड बैलेंसर्स / आदि उसके लिए तैयार न हों।
लुसियो पावा

मैं पायथन / पीएचपी प्रोग्रामर हूं और मैं सॉकेट्स और नोड के लिए नया हूं, सवाल यह है कि हमें प्रत्येक सेकंड में एक ही उपयोगकर्ता के seq नंबर को बढ़ाने की आवश्यकता क्यों है? यह सिर्फ डेमो के लिए है?
उमैर

1
@ यह केवल डेमो उद्देश्यों के लिए है, कोई वास्तविक क्रम संख्या बढ़ाने की आवश्यकता नहीं है। यह केवल यह दिखाना था कि आप प्रत्येक ग्राहक को सामान भेज सकते हैं और वे इसे प्राप्त करेंगे।
लुसियो पावा

मैं इस उदाहरण में नहीं देखता कि कैसे एक विशिष्ट ग्राहक केवल और केवल दूसरे ग्राहक को संदेश भेजता है। प्रत्येक क्लाइंट केवल आपके स्वयं के अनुक्रम नंबर को जानता है जैसा कि आपने नाम दिया था और इसे डेमो के लिए बनाया था, और इस क्रम संख्या से सॉकेट आईडी में कोई नक्शा नहीं है जो क्लाइंट को उस सॉकेट आईडी के साथ एक संदेश भेजने के लिए आवश्यक है।
सेल्कुक

35

आप उपयोग कर सकते हैं

// भेजने वाले-ग्राहक को ही संदेश भेजें

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

// या आप प्रेषक सहित सभी श्रोताओं को भेज सकते हैं

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

// भेजने वाले को छोड़कर सभी श्रोताओं को भेजें

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

// या आप इसे एक कमरे में भेज सकते हैं

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


मेरे लिए काम किया, मुझे "const सॉकेट = आवश्यकता ('सॉकेट.आईओ') (http)" भी जोड़ना पड़ा; मेरे server.js फ़ाइल में।
21

35

1.0 में आपको उपयोग करना चाहिए:

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

1
हां !!!, पहले io.sockets.sockets [socketid] .emit () काम किया था, लेकिन इसने मुझे socket.io के नए संस्करण में अपरिभाषित वस्तु त्रुटियां दीं। Io.sockets.connected कार्यों में परिवर्तन।
फ्रैगल

टाइपस्क्रिप्ट का उपयोग करने वालों के लिए, यह वर्तमान में टाइपिंग के अनुसार इसके लिए 'विहित' एपीआई है।
एवी चेरी

लेकिन मुझे एक त्रुटि प्राप्त हुई: io.sockets.connected ["JgCoFX9AiCND_ZhdAAAC"]। emit ("सॉकेटफ्रॉमसर्वर", जानकारी); ^ टाइपराइटर: अपरिभाषित की संपत्ति 'एमिट' नहीं पढ़ सकते हैं
आरजे

यह शायद इस तथ्य के कारण है कि आपी ने अद्यतन किया है io.sockets.connected["something"]और इसकी emitविधि और इसके जैसी कोई वस्तु नहीं है।
सेल्कुक

12

हम जो भी संस्करण का उपयोग कर रहे हैं यदि हम सिर्फ कंसोल.लॉग () "io" ऑब्जेक्ट का उपयोग करते हैं जो हम अपने सर्वर साइड नोडज कोड में उपयोग करते हैं, [जैसे io.on ('कनेक्शन', फ़ंक्शन (सॉकेट) {...});] , हम देख सकते हैं कि "io" सिर्फ एक json ऑब्जेक्ट है और कई चाइल्ड ऑब्जेक्ट हैं जहाँ सॉकेट आईडी और सॉकेट ऑब्जेक्ट संग्रहीत हैं।

मैं socket.io संस्करण 1.3.5, btw का उपयोग कर रहा हूं।

यदि हम io ऑब्जेक्ट में देखते हैं, तो इसमें,

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

यहां हम सॉकेट्स "B5AC9w0sYmOGWe4fAAAA" आदि देख सकते हैं, इसलिए हम कर सकते हैं,

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

फिर, आगे के निरीक्षण पर हम खंडों को देख सकते हैं,

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

तो, हम यहाँ से एक सॉकेट प्राप्त कर सकते हैं

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

इसके अलावा, हमारे पास इंजन है,

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

तो, हम भी लिख सकते हैं,

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

इसलिए, मुझे लगता है कि हम उपरोक्त 3 तरीकों में से किसी में भी अपना लक्ष्य प्राप्त कर सकते हैं,

  1. io.sockets.connected [socketid] .emit (); या
  2. io.eio.clients [socketid] .emit (); या
  3. io.engine.clients [socketid] .emit ();

लेकिन मुझे यह त्रुटि मिली: io.eio.clients ["JgCoFX9AiCND_ZhdACAC"]। emit ("सॉकेटफ्रॉम सेवर", जानकारी); ^ टाइपर्रर: अपरिभाषित की संपत्ति 'एमिट' नहीं पढ़ सकते हैं
आरजे

वर्तमान में (संस्करण 2.1.1 के साथ) यह केवल सॉकेट्स के लिए काम करता है। जुड़ा हुआ है, लेकिन अन्य दो नहीं।
जेम्स

10

तुम यह केर सकते हो

सर्वर पर।

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 "});
    }

और क्लाइंट पर, इसे संभालना बहुत आसान है।

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)
    })

7

संस्करण 1.4.5 के रूप में, सुनिश्चित करें कि आप io.to () में एक ठीक से उपसर्ग किए गए सॉकेट प्रदान करते हैं। मैं सॉकेट ले रहा था ग्राहक डीबग में लॉग इन किया और यह उपसर्ग के बिना था इसलिए मैंने हमेशा के लिए खोज समाप्त कर दिया जब तक मुझे पता नहीं चला! तो आप इसे इस तरह से कर सकते हैं यदि आपके पास ईद उपसर्ग नहीं है:

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

6

io.sockets.sockets [socket.id] .emit (...) ने मेरे लिए v0.9 में काम किया


ढेर अतिप्रवाह में आपका स्वागत है। यह उत्तर मौजूदा उत्तरों में बहुत अधिक सापेक्षता नहीं देता है। एक बार जब आपके पास अधिक प्रतिष्ठा है , तो आप अन्य लोगों के पोस्ट पर टिप्पणी कर पाएंगे । यह एक टिप्पणी के लिए बेहतर अनुकूल लगता है।
जेरी

2

इसके अलावा, आप ग्राहकों refferences रख सकते हैं। लेकिन यह आपके स्मारक को व्यस्त बनाता है।

एक खाली ऑब्जेक्ट बनाएं और उसमें अपने क्लाइंट सेट करें।

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];
  });

फिर ऑब्जेक्ट से आईडी द्वारा अपने विशिष्ट क्लाइंट को कॉल करें

myClientList[specificId].emit("blabla","somedata");

0

सॉकेट.आईओ आपको आपकी सॉकेट्स को "नेमस्पेस" करने की अनुमति देता है, जिसका अर्थ अनिवार्य रूप से विभिन्न समापन बिंदुओं या रास्तों को निर्दिष्ट करना है।

यह मदद कर सकता है: http://socket.io/docs/rooms-and-namespaces/

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.