Websocket 전송 안정성 (재 연결 중 Socket.io 데이터 손실)


81

익숙한

NodeJS, Socket.io

문제

Socket.io를 통해 앱에 연결된 두 명의 사용자 U1U2 가 있다고 가정 해보십시오. 알고리즘은 다음과 같습니다.

  1. U1 이 인터넷 연결이 완전히 끊어짐 (예 : 인터넷 끄기)
  2. U2U1에 메시지를 보냅니다 .
  3. U1 은 인터넷이 다운 되었기 때문에 아직 메시지를받지 못합니다.
  4. 서버 가 하트 비트 시간 초과로 U1 연결 끊김을 감지합니다.
  5. U1 이 socket.io에 다시 연결됩니다.
  6. U1U2 로부터 메시지를받지 못합니다 . 4 단계에서 잃어버린 것 같습니다.

가능한 설명

왜 그런지 이해한다고 생각합니다.

  • 4 단계에서 서버 는 소켓 인스턴스와 U1에 대한 메시지 큐 도 종료합니다.
  • 또한 5 단계에서 U1서버는 새 연결을 생성하므로 (재사용되지 않음) 메시지가 여전히 대기열에 있어도 이전 연결은 손실됩니다.

도움이 필요하다

이런 종류의 데이터 손실을 어떻게 방지 할 수 있습니까? 사람들이 앱에 영원히 매달리지 않기 때문에 저는 hearbeats를 사용해야합니다. 또한 새 버전의 앱을 배포 할 때 다운 타임이 전혀 발생하지 않기를 원하기 때문에 다시 연결할 수있는 가능성을 제공해야합니다.

추신 : 내가 "메시지"라고 부르는 것은 데이터베이스에 저장할 수있는 단순한 문자 메시지가 아니라 전달이 보장되어야하는 귀중한 시스템 메시지이거나 UI가 망가진 것입니다.

감사!


추가 1

이미 사용자 계정 시스템이 있습니다. 게다가 내 응용 프로그램은 이미 복잡합니다. 오프라인 / 온라인 상태를 추가해도 도움이되지 않습니다. 이미 이런 종류의 항목이 있기 때문입니다. 문제는 다릅니다.

2 단계를 확인하십시오.이 단계에서 U1이 오프라인 상태인지 여부 는 기술적으로 말할 수 없습니다 . 그는 인터넷 연결이 끊어졌을 뿐이고 인터넷 상태가 좋지 않아 2 초 동안 말할 수 있습니다. 그래서 U2는 그에게 메시지를 보내지 만 U1은 그에게 아직 인터넷이 다운되어 있기 때문에 메시지를받지 못합니다 (3 단계). 오프라인 사용자를 감지하려면 4 단계가 필요합니다. 예를 들어 시간 제한은 60 초입니다. 결국 10 초 후에 U1에 대한 인터넷 연결이 설정되고 socket.io에 다시 연결됩니다. 그러나 U1 서버에서 시간 초과로 연결이 끊어 졌기 때문에 U2의 메시지는 공간에서 손실됩니다.

그게 문제입니다. 100 % 배송하고 싶지 않습니다.


해결책

  1. 임의의 emitID로 식별되는 {} 사용자에서 방출 (방출 이름 및 데이터)을 수집하십시오. 방출 보내기
  2. 클라이언트 측에서 방출을 확인하십시오 (emitID를 사용하여 서버로 방출을 다시 보냅니다).
  3. 확인 된 경우-emitID로 식별 된 {}에서 오브젝트 삭제
  4. 사용자가 다시 연결 한 경우-이 사용자에 대해 {}을 확인하고 {}의 각 개체에 대해 1 단계를 실행하여 반복합니다.
  5. 연결이 끊어 지거나 연결되었을 때 필요한 경우 사용자를 위해 {} 플러시
// Server
const pendingEmits = {};

socket.on('reconnection', () => resendAllPendingLimits);
socket.on('confirm', (emitID) => { delete(pendingEmits[emitID]); });

// Client
socket.on('something', () => {
    socket.emit('confirm', emitID);
});

솔루션 2 (종류)

2020 년 2 월 1 일에 추가되었습니다.

이것이 실제로 Websockets에 대한 솔루션은 아니지만 누군가가 여전히 편리하다고 생각할 수 있습니다. Websockets에서 SSE + Ajax로 마이그레이션했습니다. SSE를 사용하면 클라이언트에서 연결하여 지속적인 TCP 연결을 유지하고 서버에서 실시간으로 메시지를받을 수 있습니다. 클라이언트에서 서버로 메시지를 보내려면 Ajax를 사용하면됩니다. 대기 시간 및 오버 헤드와 같은 단점이 있지만 SSE는 TCP 연결이기 때문에 안정성을 보장합니다.

Express를 사용하기 때문에 SSE https://github.com/dpskvn/express-sse 에이 라이브러리를 사용 하지만 자신에게 맞는 라이브러리를 선택할 수 있습니다.

SSE는 IE 및 대부분의 Edge 버전에서 지원되지 않으므로 https://github.com/Yaffle/EventSource와 같은 polyfill이 필요합니다 .


사실입니다. 그러나 socket.io는 실제로는 전송 프로토콜 일뿐입니다. 그것만으로는 일관되고 안정적인 메시지 전달을 보장 할 수 없습니다. pub-sub (publish-subscribe) 구조와 메시지 큐를 살펴보고 읽어야합니다. 실제로 메시지를 저장하기 위해 redis와 같은 영구 데이터베이스를 사용합니다.
user568109 dec.

그럼 pubsub가이 문제를 해결할까요? 포괄적 인 답변을 작성하고 해결책이 작동하면 현상금 (50 점)을 받게됩니다.
igorpavlov

8
이러한 아름답게 구성 질문
케이티

1
감사합니다. 나는 받아 들여진 대답이 나를 위해 일한다고 말해야한다. 현재 제안 된 방식을 사용하고 있으며 문제가 없습니다.
igorpavlov

안녕하세요 이고르! Node.js와 Socket.io를 처음 사용합니다. 가능한 경우 당신은 당신의 코드 :) 보여줄 수
Eazy

답변:


103

다른 사람들은 다른 답변과 의견에서 이에 대해 암시했지만 근본적인 문제는 Socket.IO가 전달 메커니즘 일 뿐이며 안정적인 전달을 위해 단독으로 의존 할 수 없다는 것입니다. 메시지가 클라이언트에 성공적으로 전달되었는지 확인하는 유일한 사람 은 클라이언트 자체 입니다. 이런 종류의 시스템에 대해 다음과 같은 주장을하는 것이 좋습니다.

  1. 메시지는 클라이언트에게 직접 전송되지 않습니다. 대신 서버로 전송되어 일종의 데이터 저장소에 저장됩니다.
  2. 클라이언트는 다시 연결할 때 "내가 놓친 내용"을 물어볼 책임이 있으며 데이터 저장소에 저장된 메시지를 쿼리하여 상태를 업데이트합니다.
  3. 수신자 클라이언트가 연결되어있는 동안 메시지가 서버로 전송되면 해당 메시지는 클라이언트 에게 실시간으로 전송됩니다.

물론, 애플리케이션의 필요에 따라이 부분을 조정할 수 있습니다. 예를 들어 Redis 목록 또는 메시지에 대해 정렬 된 집합을 사용하고 클라이언트가 작동 중이라는 사실을 알고있는 경우이를 지울 수 있습니다. 현재까지.


다음은 몇 가지 예입니다.

행복한 길 :

  • U1과 U2는 모두 시스템에 연결되어 있습니다.
  • U2는 U1이 수신해야하는 서버에 메시지를 보냅니다.
  • 서버는 일종의 영구 저장소에 메시지를 저장하여 일종의 타임 스탬프 또는 순차 ID로 U1에 표시합니다.
  • 서버는 Socket.IO를 통해 U1에 메시지를 보냅니다.
  • U1의 클라이언트는 (아마도 Socket.IO 콜백을 통해) 메시지를 받았음을 확인합니다.
  • 서버는 데이터 저장소에서 지속되는 메시지를 삭제합니다.

오프라인 경로 :

  • U1이 인터넷 연결을 끊습니다.
  • U2는 U1이 수신해야하는 서버에 메시지를 보냅니다.
  • 서버는 일종의 영구 저장소에 메시지를 저장하여 일종의 타임 스탬프 또는 순차 ID로 U1에 표시합니다.
  • 서버는 Socket.IO를 통해 U1에 메시지를 보냅니다.
  • U1의 클라이언트 는 오프라인이기 때문에 영수증을 확인 하지 않습니다 .
  • 아마도 U2는 U1에게 몇 가지 메시지를 더 보냅니다. 모두 동일한 방식으로 데이터 저장소에 저장됩니다.
  • U1이 다시 연결되면 서버에 "내가 본 마지막 메시지는 X / 상태 X가 있습니다. 무엇을 놓쳤습니까?"
  • 서버는 U1의 요청에 따라 데이터 저장소에서 누락 된 모든 메시지를 U1에 보냅니다.
  • U1의 클라이언트는 수신을 확인하고 서버는 데이터 저장소에서 해당 메시지를 제거합니다.

보장 된 전달을 원하는 경우 연결이 실제로 중요하지 않은 방식으로 시스템을 설계하는 것이 중요하며 실시간 전달은 단순히 보너스 일뿐입니다 . 이것은 거의 항상 일종의 데이터 저장소를 포함합니다. user568109가 의견에서 언급했듯이 메시지의 저장 및 전달을 추상화하는 메시징 시스템이 있으며 이러한 사전 구축 된 솔루션을 살펴볼 가치가 있습니다. (아직도 Socket.IO 통합을 직접 작성해야합니다.)

데이터베이스에 메시지를 저장하는 데 관심이 없다면 메시지를 로컬 배열에 저장하지 않아도됩니다. 서버는 U1에게 메시지를 보내려고 시도하고 U1의 클라이언트가 메시지를 받았음을 확인할 때까지 "보류중인 메시지"목록에 저장합니다. 클라이언트가 오프라인 상태 인 경우 다시 돌아 왔을 때 서버에 "연결이 끊겼습니다. 놓친 내용을 보내주세요"라고 알려주고 서버는 이러한 메시지를 반복 할 수 있습니다.

다행히 Socket.IO는 클라이언트가 네이티브 JS 콜백처럼 보이는 메시지에 "응답"할 수있는 메커니즘을 제공합니다. 다음은 의사 코드입니다.

// server
pendingMessagesForSocket = [];

function sendMessage(message) {
  pendingMessagesForSocket.push(message);
  socket.emit('message', message, function() {
    pendingMessagesForSocket.remove(message);
  }
};

socket.on('reconnection', function(lastKnownMessage) {
  // you may want to make sure you resend them in order, or one at a time, etc.
  for (message in pendingMessagesForSocket since lastKnownMessage) {
    socket.emit('message', message, function() {
      pendingMessagesForSocket.remove(message);
    }
  }
});

// client
socket.on('connection', function() {
  if (previouslyConnected) {
    socket.emit('reconnection', lastKnownMessage);
  } else {
    // first connection; any further connections means we disconnected
    previouslyConnected = true;
  }
});

socket.on('message', function(data, callback) {
  // Do something with `data`
  lastKnownMessage = data;
  callback(); // confirm we received the message
});

이는 영구 데이터 저장소가없는 마지막 제안과 매우 유사합니다.


이벤트 소싱 의 개념에 관심이있을 수도 있습니다 .


2
나는 고객이 반드시 배송을 확인해야한다는 진술과 함께 최종 포괄적 인 답변을 기다렸습니다. 정말 다른 방법은없는 것 같습니다.
igorpavlov

도와 주셔서 기쁩니다! 질문이 있으시면 저에게 핑을주세요 .
Michelle Tilley

이것은 일대일 채팅 시나리오에서 작동합니다. 여러 사용자에게 메시지가 전송 된 방의 예. broadcast / socket.in은 콜백을 지원하지 않습니다. 그래서 우리는 그 상황을 어떻게 처리합니까? 이것에 대한 내 질문. ( stackoverflow.com/questions/43186636/… )
jit

2

Michelle의 대답은 거의 정답이지만 고려해야 할 몇 가지 중요한 사항이 있습니다. 스스로에게 물어볼 주요 질문은 "내 앱에서 사용자와 소켓간에 차이가 있습니까?"입니다. 또 다른 방법은 "로그인 한 각 사용자가 한 번에 둘 이상의 소켓 연결을 가질 수 있습니까?"입니다.

웹 세계에서는이를 방지하는 무언가를 특별히 배치하지 않는 한 단일 사용자가 다중 소켓 연결을 가질 가능성이 항상있을 것입니다. 가장 간단한 예는 사용자가 동일한 페이지의 두 개의 탭이 열려있는 경우입니다. 이러한 경우에는 인간 사용자에게 메시지 / 이벤트를 한 번만 보내는 데 신경 쓰지 않습니다. 각 탭에서 콜백을 실행하여 UI 상태를 업데이트 할 수 있도록 해당 사용자의 각 소켓 인스턴스에 메시지 / 이벤트를 보내야합니다. 아마도 이것은 특정 응용 프로그램에 대한 우려가 아니지만 내 직감은 그것이 대부분의 경우라고 말합니다. 이것이 걱정된다면 계속 읽어보십시오 ....

이를 해결하려면 (데이터베이스를 영구 저장소로 사용한다고 가정) 3 개의 테이블이 필요합니다.

  1. 사용자-실제 사람들과 1 : 1로
  2. 클라이언트- 소켓 서버에 대한 단일 연결을 가질 있는 "탭"을 나타냅니다 . (모든 '사용자'는 여러 개를 가질 수 있습니다.)
  3. messages-클라이언트에 보내야하는 메시지 (사용자 나 소켓에 보내야하는 메시지가 아님)

사용자 테이블은 앱에 필요하지 않은 경우 선택 사항이지만 OP는 테이블이 있다고 말했습니다.

적절하게 정의해야하는 또 다른 것은 "소켓 연결이란 무엇입니까?", "소켓 연결은 언제 생성됩니까?", "소켓 연결은 언제 재사용됩니까?"입니다. Michelle의 의사 코드는 소켓 연결을 재사용 할 수있는 것처럼 보입니다. Socket.IO를 사용하면 재사용 할 수 없습니다. 나는 많은 혼란의 원인이되는 것을 보았다. Michelle의 예가 의미가있는 실제 시나리오가 있습니다. 그러나 나는 그러한 시나리오가 드물다고 상상해야합니다. 실제로 발생하는 것은 소켓 연결이 끊어지면 해당 연결, ID 등이 재사용되지 않을 때입니다. 따라서 해당 소켓에 대해 특별히 표시된 메시지는 원래 연결 한 클라이언트가 다시 연결될 때 완전히 새로운 연결과 새 ID를 얻으므로 누구에게도 전달되지 않습니다. 이것은

따라서 웹 기반 예제의 경우 여기에 권장하는 단계가 있습니다.

  • 사용자가 소켓 연결을 만들 수있는 클라이언트 (일반적으로 단일 웹 페이지)를로드 할 때 사용자 ID에 연결된 클라이언트 데이터베이스에 행을 추가합니다.
  • 사용자가 실제로 소켓 서버에 연결하면 연결 요청과 함께 클라이언트 ID를 서버에 전달합니다.
  • 서버는 사용자의 연결이 허용되고 클라이언트 테이블의 클라이언트 행이 연결에 사용 가능한지 확인하고 그에 따라 허용 / 거부해야합니다.
  • Socket.IO에서 생성 한 소켓 ID로 클라이언트 행을 업데이트합니다.
  • 클라이언트 ID에 연결된 메시지 테이블의 항목을 보냅니다. 초기 연결에는 아무것도 없지만 다시 연결하려는 클라이언트의 것이면 일부가있을 수 있습니다.
  • 메시지를 해당 소켓으로 보내야 할 때마다 생성 한 클라이언트 ID (소켓 ID가 아님)에 연결된 메시지 테이블에 행을 추가하십시오.
  • 메시지를 내보내고 승인이있는 클라이언트를 수신합니다.
  • 승인을 받으면 메시지 테이블에서 해당 항목을 삭제하십시오.
  • 일부가 지적했듯이 기술적으로 가능성이 있기 때문에 서버에서 보낸 중복 메시지를 버리는 클라이언트 측에 몇 가지 논리를 만들 수 있습니다.
  • 그런 다음 클라이언트가 소켓 서버에서 연결이 끊어지면 (의도적으로 또는 오류를 통해) 클라이언트 행을 삭제하지 말고 소켓 ID를 최대한 지워야합니다. 동일한 클라이언트가 다시 연결을 시도 할 수 있기 때문입니다.
  • 클라이언트가 다시 연결을 시도 할 때 원래 연결 시도와 함께 보낸 동일한 클라이언트 ID를 보냅니다. 서버는 이것을 초기 연결처럼 볼 것입니다.
  • 클라이언트가 파괴되면 (사용자가 탭을 닫거나 다른 곳으로 이동)이 클라이언트에 대한 클라이언트 행과 모든 메시지를 삭제합니다. 이 단계는 약간 까다로울 수 있습니다.

마지막 단계가 까다롭기 때문에 (적어도 예전에는 그런 일을 한 적이 없습니다) 그리고 클라이언트 행을 정리하지 않고 연결을 끊고 시도하지 않는 정전과 같은 경우가 있기 때문입니다. 동일한 클라이언트 행과 다시 연결하려면-오래된 클라이언트 및 메시지 행을 정리하기 위해 주기적으로 실행되는 무언가를 원할 것입니다. 또는 모든 클라이언트와 메시지를 영구적으로 저장하고 해당 상태를 적절하게 표시 할 수 있습니다.

한 명의 사용자가 두 개의 탭을 연 경우 서버가 각 사용자가 아닌 각 클라이언트가 메시지를 수신했는지 알아야하기 때문에 각기 다른 클라이언트에 대해 표시된 메시지 테이블에 두 개의 동일한 메시지를 추가하게됩니다.


1

이미 사용자 계정 시스템이있는 것 같습니다. 온라인 / 오프라인 계정을 알고 있으면 연결 / 연결 해제 이벤트를 처리 할 수 ​​있습니다.

따라서 해결책은 각 사용자의 데이터베이스에 온라인 / 오프라인 및 오프라인 메시지를 추가하는 것입니다.

chatApp.onLogin(function (user) {
   user.readOfflineMessage(function (msgs) {
       user.sendOfflineMessage(msgs, function (err) {
           if (!err) user.clearOfflineMessage();
       });
   })
});

chatApp.onMessage(function (fromUser, toUser, msg) {
   if (user.isOnline()) {
      toUser.sendMessage(msg, function (err) {
          // alert CAN NOT SEND, RETRY?
      });
   } else {
      toUser.addToOfflineQueue(msg);
   }
})

내 질문의 "추가 1"섹션을 읽어보십시오. 나는 당신의 대답이 해결책이라고 생각하지 않습니다.
igorpavlov

흥미 롭습니다. 저는 웹 RTC를 사용하여 지금 내 채팅 프로젝트를 시작합니다. :->
damphat

WebRTC에서도 채굴합니다. 그러나이 맥락에서는 중요하지 않습니다. 아 ... 모든 사람들이 안정적인 인터넷을 가지고 있다면 ... Speedtest에서 사용자가 100Mbps를 사용하면 너무 답답하지만 실제로 ping을 시도하면 20 % 패킷 손실이 발생합니다. 누가 그런 인터넷이 필요합니까? =)
igorpavlov

0

여기를보세요 : Handle browser reload socket.io .

내가 생각 해낸 솔루션을 사용할 수 있다고 생각합니다. 올바르게 수정하면 원하는대로 작동합니다.


흥미 롭군요.이 질문을 찾을 수 없었지만 몇 시간 동안 검색했습니다. 살펴 보겠습니다!
igorpavlov

이미 이런 종류의 아키텍처를 사용하고있는 것 같습니다. 내가 설명한 정확한 문제를 해결하지 못합니다.
igorpavlov

0

내가 원하는 것은 각 사용자에 대해 재사용 가능한 소켓을 갖는 것입니다.

고객:

socket.on("msg", function(){
    socket.send("msg-conf");
});

섬기는 사람:

// Add this socket property to all users, with your existing user system
user.socket = {
    messages:[],
    io:null
}
user.send = function(msg){ // Call this method to send a message
    if(this.socket.io){ // this.io will be set to null when dissconnected
        // Wait For Confirmation that message was sent.
        var hasconf = false;
        this.socket.io.on("msg-conf", function(data){
            // Expect the client to emit "msg-conf"
            hasconf = true;
        });
        // send the message
        this.socket.io.send("msg", msg); // if connected, call socket.io's send method
        setTimeout(function(){
            if(!hasconf){
                this.socket = null; // If the client did not respond, mark them as offline.
                this.socket.messages.push(msg); // Add it to the queue
            }
        }, 60 * 1000); // Make sure this is the same as your timeout.

    } else {
        this.socket.messages.push(msg); // Otherwise, it's offline. Add it to the message queue
    }
}
user.flush = function(){ // Call this when user comes back online
    for(var msg in this.socket.messages){ // For every message in the queue, send it.
        this.send(msg);
    }
}
// Make Sure this runs whenever the user gets logged in/comes online
user.onconnect = function(socket){
    this.socket.io = socket; // Set the socket.io socket
    this.flush(); // Send all messages that are waiting
}
// Make sure this is called when the user disconnects/logs out
user.disconnect = function(){
    self.socket.io = null; // Set the socket to null, so any messages are queued not send.
}

그런 다음 연결 해제 사이에 소켓 큐가 보존됩니다.

각 사용자 socket속성을 데이터베이스에 저장 하고 메서드를 사용자 프로토 타입의 일부로 만듭니다. 데이터베이스는 중요하지 않습니다. 사용자를 저장했지만 저장하십시오.

이렇게하면 메시지를 보낸 것으로 표시하기 전에 클라이언트의 확인을 요청하여 Additon 1에서 언급 한 문제를 방지 할 수 있습니다. 정말로 원하면 각 메시지에 ID를 부여하고 클라이언트가 메시지 ID를 msg-conf에 보낸 다음 확인하도록 할 수 있습니다.

이 예에서는 user모든 사용자가 복사 된 템플릿 사용자이거나 사용자 프로토 타입과 유사합니다.

참고 : 이것은 테스트되지 않았습니다.


실제로 "사용자"변수가 무엇인지 말씀해 주시겠습니까?
igorpavlov

사실 당신이 내 질문을 제대로했다고 생각합니다. 그러나 각 코드에 대해 몇 가지 주석을 제공 할 수 있습니까? 나는 그것을 내 코드에 어떻게 통합 할 수 있는지 아직 이해하지 못한다. 또한 데이터베이스에 저장해야하며 어떤 종류의 데이터베이스를 의미합니까? Redis 또는 Mongo 일 수 있거나 중요하지 않습니까?
igorpavlov

여전히 문제가 해결되지 않습니다. 메시지가 전송되면 두 사용자 (발신자 및 수신자)가 모두 서버에 대해 온라인 상태입니다. 내 질문의 추가 1을 매우주의 깊게 읽으십시오. 이 경우 "this.socket.io"는 항상 "true"이므로 메시지가 전송되지만 수신되지는 않습니다. SENDER가 오프라인 상태가되지만 RECEIVER가 아닌 경우 문제를 해결하려고합니다. 아니면 내가 옳지 않습니까?
igorpavlov

@igorpavlov, 미안하지만 나를 오해하고 있습니다. U1이 U2에게 "안녕"메시지를 보내려고합니다 users.getUserByName("U2").send("Hi").. 그런 다음 U2가 온라인이면 U2의 socket.io가 null이 아니므로 메시지가 전송됩니다. U2의 소켓이 null이면 U2가 온라인이 될 때까지 대기열에 추가됩니다.
Ari Porad

1
@igorpavlov가 옳다고 믿습니다. 클라이언트가 실제로 연결이 끊긴 기간이 있지만 아직 하트 비트가 발생하지 않았기 때문에 서버가이를 알지 못합니다. 이 기간에, this.socket.io것입니다 하지null, 서버는 메시지를 전달하려고합니다.
Michelle Tilley

0

이미 다른 답변에서 작성했듯이 실시간을 보너스로보아야한다고 생각합니다. 시스템은 실시간 없이도 작동 할 수 있어야합니다.

저는 대기업 (ios, android, web frontend 및 .net core + postGres 백엔드)을위한 엔터프라이즈 채팅을 개발 중이며 websocket이 연결을 다시 설정하고 (소켓 uuid를 통해) 전달되지 않은 메시지를받는 방법을 개발 한 후 (대기열에 저장 됨) 더 나은 솔루션이 있다는 것을 이해했습니다. 나머지 API를 통한 재 동기화입니다.

기본적으로 나는 잃어버린 메시지를 모니터링하기 위해 각 실시간 메시지 (사용자 온라인, 타이프, 채팅 메시지 등)에 정수 태그를 사용하여 실시간으로 websocket을 사용했습니다.

클라이언트가 모 놀리 식 (+1)이 아닌 ID를 받으면 동기화되지 않았 음을 이해하므로 모든 소켓 메시지를 삭제하고 REST API를 통해 모든 관찰자의 재 동기화를 요청합니다.

이렇게하면 재 연결시 수많은 웹 소켓 메시지를 연속적으로 구문 분석 할 필요없이 오프라인 기간 동안 애플리케이션 상태의 다양한 변화를 처리 할 수 ​​있으며 동기화 될 수 있습니다 (마지막 동기화 날짜는 REST API에 의해 설정되기 때문). , 소켓에서).

유일한 까다로운 부분은 REST API를 호출하는 순간부터 서버가 응답하는 순간까지 실시간 메시지를 모니터링하는 것입니다. DB에서 읽은 내용이 클라이언트로 돌아가는 데 시간이 걸리고 그 동안 변형이 발생할 수 있으므로 캐시해야하기 때문입니다. 그리고 고려했습니다.

우리는 몇 달 후에 생산에 들어갈 예정이며, 그때까지 다시 잠들기를 바랍니다. :)


-2

나중에이 물건을보고 다른 경로가 더 나을 것이라고 생각했습니다.

Azure Service bus, ques 및 topic을 살펴보고 오프라인 상태를 처리하세요. 메시지는 사용자가 돌아올 때까지 기다린 다음 메시지를받습니다.

대기열을 실행하는 데 드는 비용이지만 기본 대기열의 경우 백만 작업 당 0.05 달러와 같으므로 대기열 시스템을 작성하는 데 필요한 작업 시간에서 개발 비용이 더 많이들 것입니다. https://azure.microsoft.com/en-us/pricing/details/service-bus/

그리고 azure bus에는 PHP, C #, Xarmin, Anjular, Java Script 등에 대한 라이브러리와 예제가 있습니다.

따라서 서버는 메시지를 보내고 추적에 대해 걱정할 필요가 없습니다. 클라이언트는 필요한 경우 부하 분산을 처리 할 수있는 수단으로 메시지를 사용하여 다시 보낼 수 있습니다.


나에게는 제품 배치처럼 보입니다. 누군가는 이것이 도움이 될 수 있지만 이것은 기술이 아니라 전체 서비스도 유료입니다.
igorpavlov

-2

이 방출 채팅 목록을 사용해보십시오

io.on('connect', onConnect);

function onConnect(socket){

  // sending to the client
  socket.emit('hello', 'can you hear me?', 1, 2, 'abc');

  // sending to all clients except sender
  socket.broadcast.emit('broadcast', 'hello friends!');

  // sending to all clients in 'game' room except sender
  socket.to('game').emit('nice game', "let's play a game");

  // sending to all clients in 'game1' and/or in 'game2' room, except sender
  socket.to('game1').to('game2').emit('nice game', "let's play a game (too)");

  // sending to all clients in 'game' room, including sender
  io.in('game').emit('big-announcement', 'the game will start soon');

  // sending to all clients in namespace 'myNamespace', including sender
  io.of('myNamespace').emit('bigger-announcement', 'the tournament will start soon');

  // sending to individual socketid (private message)
  socket.to(<socketid>).emit('hey', 'I just met you');

  // sending with acknowledgement
  socket.emit('question', 'do you think so?', function (answer) {});

  // sending without compression
  socket.compress(false).emit('uncompressed', "that's rough");

  // sending a message that might be dropped if the client is not ready to receive messages
  socket.volatile.emit('maybe', 'do you really need it?');

  // sending to all clients on this node (when using multiple nodes)
  io.local.emit('hi', 'my lovely babies');

};

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