socket.io 및 node.js를 사용하여 특정 클라이언트에게 메시지 보내기


191

socket.io 및 node.js로 작업하고 있으며 지금까지는 꽤 좋아 보이지만 서버에서 특정 클라이언트로 메시지를 보내는 방법을 모르겠습니다.

client.send(message, receiverSessionId)

그러나 방법 .send()이나 .broadcast()방법 모두 내 필요를 제공 하지 않는 것 같습니다.

가능한 해결책으로 찾은 것은 .broadcast()메서드가 메시지를 보내지 않는 SessionId 배열을 두 번째 매개 변수로 받아들이므로 그 순간에 연결된 모든 SessionId가있는 배열을 서버에 전달할 수 있다는 것입니다. 메시지를 보내길 원하지만 더 나은 해결책이 있어야한다고 생각합니다.

어떤 아이디어?

답변:


95

글쎄, 당신은 (놀람)에 대한 클라이언트를 잡아야합니다, 당신은 간단한 길을 갈 수 있습니다 :

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

어느 것이 깨질 지 의심 스럽지만 항상 io.clients변경 될 가능성이 있으므로 위의 내용을주의해서 사용하십시오.

또는 클라이언트를 직접 추적하므로 리스너 clients에서 자신의 객체에 클라이언트를 추가하고 connection리스너에서 제거하십시오 disconnect.

응용 프로그램에 따라 클라이언트에 더 많은 상태를 원할 수 있으므로 후자를 사용하므로 clients[id] = {conn: clientConnect, data: {...}}작업을 수행 할 수 있습니다.


6
Ivo, 좀 더 완전한 예를 지적하거나 조금 더 자세히 설명해 주시겠습니까? 이 접근법을 이해하고 싶지만이 예제에서 사용중인 변수 / 객체를 인식하지 못합니다. clients [id] = {conn : clientConnect, data : {...}}에서 clients [id]는 위의 io.clients [sessionID]에 표시된 것처럼 io 객체의 일부입니까? 또한 clientConnect 객체는 무엇입니까? 감사.
AndrewHenderson 2014

@ ivo-wetzel 안녕하세요,이 주제에 대해 저를 환영 할 수 있습니까? stackoverflow.com/questions/38817680/…
mahdi pishguy 19시 56 분

178

Ivo Wetzel의 답변이 Socket.io 0.9에서 더 이상 유효하지 않은 것 같습니다.

요컨대 이제를 저장하고 메시지를 보내는 데 socket.id사용해야 io.sockets.socket(savedSocketId).emit(...)합니다.

이것이 클러스터 Node.js 서버에서 작동하는 방법입니다.

먼저 메시지가 교차 프로세스로 이동할 수 있도록 Redis 저장소를 저장소로 설정해야합니다.

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(...)(네임 스페이스를 사용하고 있기 때문에 모르겠습니다)
Adrien Schuler

클러스터 환경에서 소켓이 속한 올바른 프로세스가 메시지를 보내는 지 어떻게 확인합니까?
Gal Ben-Haim

NGINX 또는 HAProxy @Gal Ben-Haim의 끈끈한 세션은 어떻습니까?
matanster

var holder = 새로운 socketio.RedisStore; ^ TypeError : undefined는 Object. <anonymous> (C : \ Users \ Dev \ Desktop \ nouty-server \ server.js : 108 : 14)의 Module._compile (module.js : 460 : 26)에있는 함수가 아닙니다. Function.Module의 Function.Module._load (module.js : 310 : 12)의 Module.load (module.js : 355 : 32)의 Object.Module._extensions..js (module.js : 478 : 10) runMain (module.js : 501 : 10) 시작시 (node.js : 129 : 16) node.js : 814 : 3
Lucas Bertollo

1
io.sockets.socket(socket_id)socket.io 1.0에서 제거되었습니다. github.com/socketio/socket.io/issues/1618#issuecomment-46151246
ImMathan

98

각 소켓은 이름에 대한 소켓 ID로 회의실에 참여하므로

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

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

건배


7
이것은 가장 좋은 대답이며 최신 버전의 socket.io에서 작동합니다. 멋진 속임수 시트는 여기있다 : stackoverflow.com/questions/10058226/...
blented

4
이는 '브로드 캐스트'유형의 이벤트 발생입니다. 콜백을 설정하려고하면 오류가 발생합니다. 콜백을 통해 특정 소켓에 이벤트를 보내려면 @PHPthinking의 답변을 사용하십시오 io.sockets.connected[socketid].emit();. 1.4.6으로 테스트되었습니다.
tbutcaru

그러나이 오류가 발생했습니다 : io.to [ "JgCoFX9AiCND_ZhdAAAC"]. emit ( "socketFromServe‌r", info); ^ TypeError : 정의되지 않은 'emit'속성을 읽을 수 없습니다
Raz

85

가장 단순하고 가장 우아한 솔루션

다음과 같이 쉽습니다.

client.emit("your message");

그리고 그게 다야.

그러나 어떻게? 예를 들어주세요

우리 모두가 필요로하는 것은 실제로 완전한 예이며, 그것이 따르는 것입니다. 이것은 가장 최근의 socket.io 버전 (2.0.3)으로 테스트되었으며 최신 Javascript도 사용하고 있습니다 (지금 우리 모두가 사용해야합니다).

이 예제는 서버와 클라이언트의 두 부분으로 구성됩니다. 클라이언트가 연결할 때마다 서버에서 주기적 시퀀스 번호를 받기 시작합니다. 새로운 클라이언트마다 새로운 시퀀스가 ​​시작되므로 서버는 개별적으로 클라이언트를 추적해야합니다. (가) 곳이다 "나는 특정 클라이언트에 메시지를 보낼 필요" 놀이로 제공됩니다. 코드는 이해하기 매우 간단합니다. 어디 보자.

섬기는 사람

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
답장이 너무 오래 걸려서 죄송합니다. @ingo. 8000은 웹 소켓 또는 HTTP 서버 (3000도 공통)를 테스트 할 때 노드 커뮤니티에서 사용하는 공통 포트입니다. 물론 프로덕션 환경에서 사용할 수는 있지만 게이트웨이 /로드 밸런서 등이 준비되어있는 한 실제로 어떤 포트를 사용할 수 있는지 잘 모르겠습니다.
Lucio Paiva

나는 Python / PHP 프로그래머이고 소켓과 노드를 처음 사용하는데, 질문은 왜 같은 사용자의 seq 수를 초당 증가시켜야 하는가? 데모 용입니까?
Umair

1
@Umair 그것은 데모 목적으로 만 사용되며 실제로 시퀀스 번호를 증가시킬 필요가 없습니다. 그것은 당신이 각 클라이언트에게 물건을 계속 보낼 수 있고 그들이 그것을받을 것이라는 것을 보여주기 위해서였습니다.
Lucio Paiva

이 예에서는 특정 클라이언트가 다른 클라이언트에게만 메시지를 보내는 방법을 보지 못했습니다. 각 클라이언트는 이름을 지정하고 데모 용으로 작성한 고유 한 시퀀스 번호 만 알고 있으며,이 시퀀스 번호에서 소켓 ID로 클라이언트에 메시지를 직접 보내는 데 필요한 소켓 ID 로의 맵핑이 없습니다.
Selçuk

36

당신이 사용할 수있는

// 발신자 클라이언트에게만 메시지 보내기

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 socket = require ( 'socket.io') (http);" 내 server.js 파일에 있습니다.
iPzard 2019 년

36

1.0에서는 다음을 사용해야합니다.

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

1
예 !!!, 이전에 io.sockets.sockets [socketid] .emit ()가 작동했지만 최신 버전의 socket.io에서 정의되지 않은 객체 오류가 발생했습니다. io.sockets.connected로 변경하면 작동합니다.
Fraggle

TypeScript를 사용하는 사람들은 현재 입력 유형에 따라 '정식'API입니다.
Avi Cherry

그러나 오류가 발생합니다. io.sockets.connected [ "JgCoFX9AiCND_ZhdAAAC"]. emit ( "socketFromServer", info); ^ TypeError : 정의되지 않은 'emit'속성을 읽을 수 없습니다
Raz

그것은 아마도 API가 업데이트되었고 더 이상 비슷한 객체 io.sockets.connected["something"]와 그 emit방법 이 없다는 사실 때문일 것입니다 .
Selçuk

12

우리가 서버 측 nodejs 코드에서 사용하는 "io"객체를 console.log ()하는 경우 어떤 버전을 사용하든 [예 : io.on ( 'connection', function (socket) {...});] "io"는 단지 json 객체이며 소켓 id 및 소켓 객체가 저장되는 많은 하위 객체가 있음을 알 수 있습니다.

socket.io 버전 1.3.5, btw를 사용하고 있습니다.

io 객체를 살펴보면

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

여기서 우리는 socketids "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_ZhdAAAC"]. emit ( "socketFromServer", info); ^ TypeError : 정의되지 않은 'emit'속성을 읽을 수 없습니다
Raz

현재 (버전 2.1.1) 이것은 sockets.connected에서만 작동했지만 다른 두 가지에서는 작동하지 않았습니다.
James

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 ()에 올바른 접두어 socketId를 제공해야합니다. 나는 클라이언트가 디버그하기 위해 기록한 socketId를 가지고 있었고 접두사가 없었기 때문에 내가 찾을 때까지 영원히 검색하게되었습니다! 따라서 ID가 접두사가없는 경우 다음과 같이해야 할 수도 있습니다.

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

6

io.sockets.sockets [socket.id] .emit (...)은 v0.9에서 나를 위해 일했습니다.


스택 오버플로에 오신 것을 환영합니다. 이 답변은 기존 답변과 관련이 많은 것으로 보이지 않습니다. 더 많은 평판얻으면 다른 사람의 게시물에 댓글 수 있습니다 . 이것은 주석에 더 적합한 것으로 보입니다.
jerry

2

또한 고객의 반박을 유지할 수 있습니다. 그러나 이것은 당신의 기억을 바쁘게 만듭니다.

빈 개체를 만들고 클라이언트를 설정하십시오.

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

그런 다음 객체에서 ID로 특정 클라이언트를 호출하십시오.

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.