WebSocket का उपयोग करके किसी विशिष्ट कनेक्टेड उपयोगकर्ताओं को संदेश भेजना?


82

मैंने सभी उपयोगकर्ताओं को एक संदेश प्रसारित करने के लिए एक कोड लिखा :

// websocket and http servers
var webSocketServer = require('websocket').server;

...
...
var clients = [ ];

var server = http.createServer(function(request, response) {
    // Not important for us. We're writing WebSocket server, not HTTP server
});
server.listen(webSocketsServerPort, function() {
  ...
});

var wsServer = new webSocketServer({
    // WebSocket server is tied to a HTTP server. 
    httpServer: server
});

// This callback function is called every time someone
// tries to connect to the WebSocket server
wsServer.on('request', function(request) {
...
var connection = request.accept(null, request.origin); 
var index = clients.push(connection) - 1;
...

कृपया ध्यान दें:

  • मेरे पास कोई उपयोगकर्ता संदर्भ नहीं है, लेकिन केवल एक कनेक्शन है।
  • सभी उपयोगकर्ता कनेक्शन में संग्रहीत हैं array

लक्ष्य : मान लीजिए कि Node.js सर्वर एक विशिष्ट ग्राहक (जॉन) को संदेश भेजना चाहता है। जॉन को किस कनेक्शन से NodeJs सर्वर पता होगा? Node.js सर्वर भी जॉन को नहीं जानता है। यह सब देखता है कनेक्शन है।

इसलिए, मेरा मानना ​​है कि अब, मुझे उपयोगकर्ताओं को केवल उनके कनेक्शन द्वारा स्टोर नहीं करना चाहिए, इसके बजाय, मुझे एक ऑब्जेक्ट स्टोर करने की आवश्यकता है, जिसमें ऑब्जेक्ट userIdऔर connectionऑब्जेक्ट शामिल होंगे ।

विचार:

  • जब पृष्ठ लोड करना समाप्त कर लेता है (DOM तैयार) - Node.js सर्वर से एक कनेक्शन स्थापित करें।

  • जब Node.js सर्वर कनेक्शन स्वीकार करता है - एक अद्वितीय स्ट्रिंग उत्पन्न करता है और इसे क्लाइंट ब्राउज़र को भेजता है। किसी ऑब्जेक्ट में उपयोगकर्ता कनेक्शन और अद्वितीय स्ट्रिंग संग्रहीत करें। जैसे{UserID:"6", value: {connectionObject}}

  • क्लाइंट की ओर से, जब यह संदेश आता है - इसे एक छिपे हुए क्षेत्र या कुकी में संग्रहीत करें। (NodeJs सर्वर के भावी अनुरोधों के लिए)


जब सर्वर जॉन को संदेश भेजना चाहता है:

  • शब्दकोश में जॉन के यूजरआईडी का पता लगाएं और संबंधित कनेक्शन द्वारा एक संदेश भेजें।

  • कृपया ध्यान दें कि यहां कोई भी asp.net सर्वर कोड नहीं है (संदेश तंत्र में)। केवल NodeJs। "

सवाल:

क्या यह जाने का सही तरीका है?

जवाबों:


77

यह केवल जाने का सही तरीका नहीं है, बल्कि एकमात्र तरीका है। मूल रूप से प्रत्येक कनेक्शन को एक विशिष्ट आईडी की आवश्यकता होती है। अन्यथा आप उन्हें पहचान नहीं पाएंगे, यह उतना ही सरल है।

अब आप इसका प्रतिनिधित्व कैसे करेंगे यह अलग बात है। के साथ एक वस्तु बनाना idऔर connectionगुणों को करना एक अच्छा तरीका है (मैं निश्चित रूप से इसके लिए जाऊंगा)। तुम भी idसीधे कनेक्शन वस्तु को संलग्न कर सकते हैं ।

यह भी याद रखें कि यदि आप उपयोगकर्ताओं के बीच संचार चाहते हैं, तो आपको लक्षित उपयोगकर्ता की आईडी भी भेजनी होगी, अर्थात जब उपयोगकर्ता A उपयोगकर्ता B को संदेश भेजना चाहता है, तो स्पष्ट रूप से A को B की आईडी को जानना होगा।


1
@RoyiNamir फिर से, आपके पास ज्यादा विकल्प नहीं हैं। ब्राउज़र कनेक्शन को मार देगा, इसलिए आपको वियोग और पुन: संयोजन करना होगा। जब आप ऐसा करते हैं, तो आप संभवतः किसी भी प्रकार के टाइमआउट तंत्र को लागू करना चाहते हैं (केवल समय समाप्त होने के बाद सर्वर साइड पर रैपर ऑब्जेक्ट को नष्ट करें) ऐसा होने पर अनावश्यक सूचनाओं से बचने के लिए (आप अन्य उपयोगकर्ताओं को वियोग के बारे में बताना चाहते हैं)।
अजीब

1
@RoyiNamir दो अनूठे नामों के रूप में: दूसरा विचार यह है कि ऑब्जेक्ट SOCKETS = {};को सर्वर साइड पर रखें और किसी सॉकेट को लिस्ट आईडी, यानी SOCKETS["John"] = [];और के लिए सूची में जोड़ें SOCKETS["John"].push(conn);। आपको शायद इसकी आवश्यकता होगी कि चूंकि उपयोगकर्ता कई टैब खोल सकता है।
अजीब

8
@ फ्रीक्रिश: सावधान, यह केवल एक प्रक्रिया ऐप के लिए एक अच्छा समाधान है। यदि आप कई प्रक्रियाओं (या सर्वर) का उपयोग करके अपने आवेदन को स्केल करते हैं, तो वे समान मेमोरी साझा नहीं करेंगे - इसलिए स्थानीय रूप से संग्रहीत वस्तुओं का उपयोग करने वाला पुनरावृत्ति काम नहीं करेगा। यूएआईडी को स्वयं कनेक्शन पर संग्रहीत करते हुए, सीधे सभी स्थानीय कनेक्शनों को पुनरावृत्त करना बेहतर है। इसके अलावा, स्केलिंग के लिए मैं रेडिस की सिफारिश करूंगा।
मिस्ट्री

1
क्या आप मुझे बता सकते हैं कि कनेक्शन ऑब्जेक्ट का उपयोग करके किसी विशेष क्लाइंट को संदेश कैसे भेजा जाए? मैंने उपर्युक्त के अनुसार कनेक्शन ऑब्जेक्ट में उपयोगकर्ता आईडी को सहेजा है। मैं केवल यह जानना चाहता हूं कि सर्वर से विशेष क्लाइंट को संदेश भेजते समय कनेक्शन ऑब्जेक्ट का उपयोग कैसे करें (मेरे पास उस उपयोगकर्ता का आईडी और कनेक्शन ऑब्जेक्ट है)। धन्यवाद।
वर्धन

1
@AsishAP, यह एक लंबी चर्चा है ... मेरा सुझाव है कि आप इस लेख को पढ़ने के लिए शुरू करें ताकि आप उन्मुख हो सकें और शायद अन्य प्रश्नों के लिए SO खोजें, यहाँ एक पढ़ने योग्य है
मिस्टर

39

यहाँ एक सरल चैट सर्वर निजी / प्रत्यक्ष संदेश है।

package.json

{
  "name": "chat-server",
  "version": "0.0.1",
  "description": "WebSocket chat server",
  "dependencies": {
    "ws": "0.4.x"
  }
}

server.js

var webSocketServer = new (require('ws')).Server({port: (process.env.PORT || 5000)}),
    webSockets = {} // userID: webSocket

// CONNECT /:userID
// wscat -c ws://localhost:5000/1
webSocketServer.on('connection', function (webSocket) {
  var userID = parseInt(webSocket.upgradeReq.url.substr(1), 10)
  webSockets[userID] = webSocket
  console.log('connected: ' + userID + ' in ' + Object.getOwnPropertyNames(webSockets))

  // Forward Message
  //
  // Receive               Example
  // [toUserID, text]      [2, "Hello, World!"]
  //
  // Send                  Example
  // [fromUserID, text]    [1, "Hello, World!"]
  webSocket.on('message', function(message) {
    console.log('received from ' + userID + ': ' + message)
    var messageArray = JSON.parse(message)
    var toUserWebSocket = webSockets[messageArray[0]]
    if (toUserWebSocket) {
      console.log('sent to ' + messageArray[0] + ': ' + JSON.stringify(messageArray))
      messageArray[0] = userID
      toUserWebSocket.send(JSON.stringify(messageArray))
    }
  })

  webSocket.on('close', function () {
    delete webSockets[userID]
    console.log('deleted: ' + userID)
  })
})

अनुदेश

इसे परखने के npm installलिए, इंस्टॉल करने के लिए दौड़ें ws। फिर, चैट सर्वर को शुरू करने के लिए, एक टर्मिनल टैब में चलाएं node server.js(या npm start)। फिर, एक अन्य टर्मिनल टैब में, रन करें wscat -c ws://localhost:5000/1, जहां 1कनेक्ट करने वाला उपयोगकर्ता आईडी है। फिर, एक तिहाई टर्मिनल टैब में, चलाने wscat -c ws://localhost:5000/2, और फिर, उपयोगकर्ता से एक संदेश भेजने के 2लिए 1, में प्रवेश ["1", "Hello, World!"]

कमियों

यह चैट सर्वर बहुत सरल है।

  • हठ

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

  • सुरक्षा

    यह असुरक्षित है।

    • अगर मुझे सर्वर का URL और ऐलिस की यूजर आईडी पता है, तो मैं ऐलिस को इंप्रेस कर सकता हूं, अर्थात, सर्वर को उससे कनेक्ट कर सकता हूं, जिससे मुझे उसके नए इनकमिंग मैसेज प्राप्त हो सकते हैं और उसे किसी भी यूजर को मैसेज भेज सकते हैं जिसकी यूजर आईडी भी मुझे पता है। इसे और अधिक सुरक्षित बनाने के लिए, कनेक्ट करते समय अपने एक्सेस टोकन (अपनी उपयोगकर्ता आईडी के बजाय) को स्वीकार करने के लिए सर्वर को संशोधित करें। फिर, सर्वर आपके एक्सेस टोकन से आपकी यूजर आईडी प्राप्त कर सकता है और आपको प्रमाणित कर सकता है।

    • मुझे यकीन नहीं है कि यह एक WebSocket Secure ( wss://) कनेक्शन को सपोर्ट करता है क्योंकि मैंने इसे केवल टेस्ट किया है localhost, और मुझे यकीन नहीं है कि इससे सुरक्षित रूप से कैसे कनेक्ट किया जाए localhost


क्या किसी को पता है कि एक WebSocket Secure localhost कनेक्शन कैसे बनाया जाता है?
ma11hew28

1
मुझे भी। लेकिन अगर आप 'नवीनीकरण' ... 'wupupgradReq.headers [' sec-websocket-key '' भाग के साथ काम करते हैं। ( github.com/websockets/ws/issues/310 के माध्यम से )
dirkk0

1
WS को अभ्यास में प्रारंभ करने के लिए सर्वोत्तम उदाहरण! धन्यवाद
NeverEndingQueue

1
महान उदाहरण! मैं पिछले कुछ दिनों से इस तरह के जवाब की तलाश कर रहा हूं
DIRTY DAVE

5

wsसंस्करण 3 या इसके बाद के संस्करण का उपयोग करने वाले लोगों के लिए । यदि आप @ ma11hew28 द्वारा दिए गए उत्तर का उपयोग करना चाहते हैं, तो बस इस ब्लॉक को निम्नानुसार बदलें।

webSocketServer.on('connection', function (webSocket) {
  var userID = parseInt(webSocket.upgradeReq.url.substr(1), 10)
webSocketServer.on('connection', function (webSocket, req) {
  var userID = parseInt(req.url.substr(1), 10)

ws पैकेज ऑब्जेक्ट को अनुरोध करने के लिए अपग्रेड किया गया है और आप आगे के विवरण के लिए निम्न लिंक की जांच कर सकते हैं।

संदर्भ: https://github.com/websockets/ws/issues/1114


1
आपने मुझे बहुत परेशानी से बचाया।
परिकल्पना

1

मैंने जो किया है उसे साझा करना चाहूंगा। आशा है कि यह आपका समय बर्बाद नहीं करेगा।

मैंने फ़ील्ड आईडी, IP, उपयोगकर्ता नाम, लॉगइनटाइम और लॉगआउट टाइम डेटाबेस तालिका बनाई। जब कोई उपयोगकर्ता लॉगइनटाइम में लॉग इन करता है तो वह यूनिक्सटिमस्टैम्प यूनिक्स को सही करेगा। और जब सबसे बड़े लॉगटाइम के लिए वेबसोकेट डेटाबेस चेक में कनेक्शन शुरू किया जाता है। यह आएगा उपयोगकर्ता लॉग इन।

और जब उपयोगकर्ता लॉग आउट करता है तो वह सही लॉगआउट को संग्रहीत करेगा। वह उपयोगकर्ता बन जाएगा जिसने ऐप छोड़ दिया है।

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

// when a client connects
function wsOnOpen($clientID) {
      global $Server;
      $ip = long2ip( $Server->wsClients[$clientID][6] );

      require_once('config.php');
      require_once CLASSES . 'class.db.php';
      require_once CLASSES . 'class.log.php';

      $db = new database();
      $loga = new log($db);

      //Getting the last login person time and username
      $conditions = "WHERE which = 'login' ORDER BY id DESC LIMIT 0, 1";
      $logs = $loga->get_logs($conditions);
      foreach($logs as $rows) {

              $destination = $rows["user"];
              $idh = md5("$rows[user]".md5($rows["time"]));

              if ( $clientID > $rows["what"]) {
                      $conditions = "ip = '$ip', clientID = '$clientID'  

                      WHERE logintime = '$rows[time]'";
                      $loga->update_log($conditions);
             }
      }
      ...//rest of the things
} 

0

दिलचस्प पोस्ट (मैं क्या कर रहा हूँ के समान)। हम WebS Pocket के साथ डिस्पेंसर को जोड़ने के लिए एक API (C # में) बना रहे हैं, प्रत्येक डिस्पेंसर के लिए हम एक समवर्ती छायाचित्र बनाते हैं जो WebSocket और DispucerId को संग्रहीत करता है और प्रत्येक डिस्पेंसर के लिए WebSocket बनाना और थ्रेड समस्याओं के बिना बाद में इसका उपयोग करना आसान बनाता है (विशिष्ट कार्यों को शामिल करते हुए) वेबस्केट पर जैसे गेटसेटिंग्स या रिक्वेस्ट टिकट)। आपके उदाहरण के लिए अंतर प्रत्येक तत्व को अलग करने के लिए एक सरणी के बजाय समवर्ती छाया का उपयोग है (कभी जावास्क्रिप्ट में ऐसा करने का प्रयास नहीं किया गया)। सादर,


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