실시간/WebSocket을 이용한 채팅

3. 웹소켓 이벤트

sdafdq 2023. 10. 19. 17:26

먼저, 프론트엔드와 백엔드 사이의 연결을 만들 것이다.

 

메시지를 주고 받도록 할 것이다.

 

 

 

먼저 웹 소켓은,

html 요소 이벤트 추가 하듯이,

("이벤트명", fuction)

할 수 있다.

 

웹소켓은

const wss = new WebSocketServer({server});



wss.on("connection", handleConnection)


이렇게 웹소켓서버의 on이라는 메소드로 이벤트를 추가할 수 있다. (handleConnection은 콜백함수)

추가할 수 있는 이벤트 종류는,

connection,

close,

error,

headers,

listening이 있다.

 

또, 안에 콜백 함수로 넣어주는 인자는

소켓서버 그 자체와, 소켓과, request 요청 총 3가지

 

소켓이란 연결된 사람에 대한 정보 같다. 메타 정보 같은. 또 연결 자체에 대한 정보도 있는 듯.

 

const handleListen = () => console.log(`Listening on http://localhost:3000`);

const server = http.createServer(app);
const wss = new WebSocketServer({server});

wss.on("connection", handleConnection)
server.listen(3000, handleListen);



function handleConnection(socket){
  console.log(socket);
}

일단, handleListen은 아래 보면

listen 수신하기 시작했을 때 할 콜백을 넣을 수 있는 모양이다.

 

그 다음 http서버를

웹소켓 서버로 한번 감싸주고,

웹소켓에 대한 설정을 해주는 데,

이번 같은 경우는 연결 되었을 시 handleConnection이라는 콜백을 실행하기로 했다.

그냥 socket 받아와서 콘솔로 찍는거다.

 

server.listen은

저렇게 해야 http 서버와 웹소켓 서버를 같이 돌릴 수 있나 보다.

wss말고 저걸로 해야.

 

저번에도 말 했듯, 저렇게 웹소켓서버 생성자로 http서버 감싸는 게 둘이 결합시키는 공식적인 방법임.

 

근데 뭐, connection 이벤트니 누군가와 연결이 되어야 출력을 한다.

 

 

클라이언트 쪽에서 실행할 app.js에서

const socket = new WebSocket("http://localhost:3000");

안된다.

웹소켓으로 연결 해야 한다.

 

const socket = new WebSocket("ws://localhost:3000");

잘 된다. ws가 http랑 똑같이 프로토콜 이기 때문에, ws로 넣었다.

 

 

 

이제 서버에서 연결되면 소켓 자체를 출력하도록 했었으니..

한번 보겠다. 이게 소켓객체 전체다.

WebSocket {
  _events: [Object: null prototype] { close: [Function (anonymous)] },
  _eventsCount: 1,
  _maxListeners: undefined,
  _binaryType: 'nodebuffer',
  _closeCode: 1006,
  _closeFrameReceived: false,
  _closeFrameSent: false,
  _closeMessage: <Buffer >,
  _closeTimer: null,
  _extensions: {},
  _paused: false,
  _protocol: '',
  _readyState: 1,
  _receiver: Receiver {
    _writableState: WritableState {
      objectMode: false,
      highWaterMark: 16384,
      finalCalled: false,
      needDrain: false,
      ending: false,
      ended: false,
      finished: false,
      destroyed: false,
      decodeStrings: true,
      defaultEncoding: 'utf8',
      length: 0,
      writing: false,
      corked: 0,
      sync: true,
      bufferProcessing: false,
      onwrite: [Function: bound onwrite],
      writecb: null,
      writelen: 0,
      afterWriteTickInfo: null,
      buffered: [],
      bufferedIndex: 0,
      allBuffers: true,
      allNoop: true,
      pendingcb: 0,
      constructed: true,
      prefinished: false,
      errorEmitted: false,
      emitClose: true,
      autoDestroy: true,
      errored: null,
      closed: false,
      closeEmitted: false,
      [Symbol(kOnFinished)]: []
    },
    _events: [Object: null prototype] {
      conclude: [Function: receiverOnConclude],
      drain: [Function: receiverOnDrain],
      error: [Function: receiverOnError],
      message: [Function: receiverOnMessage],
      ping: [Function: receiverOnPing],
      pong: [Function: receiverOnPong]
    },
    _eventsCount: 6,
    _maxListeners: undefined,
    _binaryType: 'nodebuffer',
    _extensions: {},
    _isServer: true,
    _maxPayload: 104857600,
    _skipUTF8Validation: false,
    _bufferedBytes: 0,
    _buffers: [],
    _compressed: false,
    _payloadLength: 0,
    _mask: undefined,
    _fragmented: 0,
    _masked: false,
    _fin: false,
    _opcode: 0,
    _totalPayloadLength: 0,
    _messageLength: 0,
    _fragments: [],
    _state: 0,
    _loop: false,
    [Symbol(kCapture)]: false,
    [Symbol(websocket)]: [Circular *1]
  },
  _sender: Sender {
    _extensions: {},
    _socket: Socket {
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: null,
      _closeAfterHandlingError: false,
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 4,
      _maxListeners: undefined,
      _writableState: [WritableState],
      allowHalfOpen: true,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: [Server],
      _server: [Server],
      parser: null,
      on: [Function (anonymous)],
      addListener: [Function (anonymous)],
      prependListener: [Function: prependListener],
      setEncoding: [Function: socketSetEncoding],
      _paused: false,
      timeout: 0,
      [Symbol(async_id_symbol)]: 58,
      [Symbol(kHandle)]: [TCP],
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: null,
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(kCapture)]: false,
      [Symbol(kSetNoDelay)]: true,
      [Symbol(kSetKeepAlive)]: false,
      [Symbol(kSetKeepAliveInitialDelay)]: 0,
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(websocket)]: [Circular *1]
    },
    _firstFragment: true,
    _compress: false,
    _bufferedBytes: 0,
    _deflating: false,
    _queue: []
  },
  _socket: <ref *2> Socket {
    connecting: false,
    _hadError: false,
    _parent: null,
    _host: null,
    _closeAfterHandlingError: false,
    _readableState: ReadableState {
      objectMode: false,
      highWaterMark: 16384,
      buffer: BufferList { head: null, tail: null, length: 0 },
      length: 0,
      pipes: [],
      flowing: true,
      ended: false,
      endEmitted: false,
      reading: true,
      constructed: true,
      sync: false,
      needReadable: true,
      emittedReadable: false,
      readableListening: false,
      resumeScheduled: true,
      errorEmitted: false,
      emitClose: false,
      autoDestroy: true,
      destroyed: false,
      errored: null,
      closed: false,
      closeEmitted: false,
      defaultEncoding: 'utf8',
      awaitDrainWriters: null,
      multiAwaitDrain: false,
      readingMore: false,
      dataEmitted: false,
      decoder: null,
      encoding: null,
      [Symbol(kPaused)]: false
    },
    _events: [Object: null prototype] {
      end: [Array],
      close: [Function: socketOnClose],
      data: [Function: socketOnData],
      error: [Function: socketOnError]
    },
    _eventsCount: 4,
    _maxListeners: undefined,
    _writableState: WritableState {
      objectMode: false,
      highWaterMark: 16384,
      finalCalled: false,
      needDrain: false,
      ending: false,
      ended: false,
      finished: false,
      destroyed: false,
      decodeStrings: false,
      defaultEncoding: 'utf8',
      length: 0,
      writing: false,
      corked: 0,
      sync: false,
      bufferProcessing: false,
      onwrite: [Function: bound onwrite],
      writecb: null,
      writelen: 0,
      afterWriteTickInfo: [Object],
      buffered: [],
      bufferedIndex: 0,
      allBuffers: true,
      allNoop: true,
      pendingcb: 1,
      constructed: true,
      prefinished: false,
      errorEmitted: false,
      emitClose: false,
      autoDestroy: true,
      errored: null,
      closed: false,
      closeEmitted: false,
      [Symbol(kOnFinished)]: []
    },
    allowHalfOpen: true,
    _sockname: null,
    _pendingData: null,
    _pendingEncoding: '',
    server: Server {
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      requestTimeout: 300000,
      headersTimeout: 60000,
      keepAliveTimeout: 5000,
      connectionsCheckingInterval: 30000,
      joinDuplicateHeaders: undefined,
      _events: [Object: null prototype],
      _eventsCount: 5,
      _maxListeners: undefined,
      _connections: 3,
      _handle: [TCP],
      _usingWorkers: false,
      _workers: [],
      _unref: false,
      allowHalfOpen: true,
      pauseOnConnect: false,
      noDelay: true,
      keepAlive: false,
      keepAliveInitialDelay: 0,
      httpAllowHalfOpen: false,
      timeout: 0,
      maxHeadersCount: null,
      maxRequestsPerSocket: 0,
      _connectionKey: '6::::3000',
      [Symbol(IncomingMessage)]: [Function: IncomingMessage],
      [Symbol(ServerResponse)]: [Function: ServerResponse],
      [Symbol(kCapture)]: false,
      [Symbol(async_id_symbol)]: 11,
      [Symbol(http.server.connections)]: ConnectionsList {},
      [Symbol(http.server.connectionsCheckingInterval)]: Timeout {
        _idleTimeout: 30000,
        _idlePrev: [TimersList],
        _idleNext: [TimersList],
        _idleStart: 1163,
        _onTimeout: [Function: bound checkConnections],
        _timerArgs: undefined,
        _repeat: 30000,
        _destroyed: false,
        [Symbol(refed)]: false,
        [Symbol(kHasPrimitive)]: false,
        [Symbol(asyncId)]: 10,
        [Symbol(triggerId)]: 1
      },
      [Symbol(kUniqueHeaders)]: null
    },
    _server: Server {
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      requestTimeout: 300000,
      headersTimeout: 60000,
      keepAliveTimeout: 5000,
      connectionsCheckingInterval: 30000,
      joinDuplicateHeaders: undefined,
      _events: [Object: null prototype],
      _eventsCount: 5,
      _maxListeners: undefined,
      _connections: 3,
      _handle: [TCP],
      _usingWorkers: false,
      _workers: [],
      _unref: false,
      allowHalfOpen: true,
      pauseOnConnect: false,
      noDelay: true,
      keepAlive: false,
      keepAliveInitialDelay: 0,
      httpAllowHalfOpen: false,
      timeout: 0,
      maxHeadersCount: null,
      maxRequestsPerSocket: 0,
      _connectionKey: '6::::3000',
      [Symbol(IncomingMessage)]: [Function: IncomingMessage],
      [Symbol(ServerResponse)]: [Function: ServerResponse],
      [Symbol(kCapture)]: false,
      [Symbol(async_id_symbol)]: 11,
      [Symbol(http.server.connections)]: ConnectionsList {},
      [Symbol(http.server.connectionsCheckingInterval)]: Timeout {
        _idleTimeout: 30000,
        _idlePrev: [TimersList],
        _idleNext: [TimersList],
        _idleStart: 1163,
        _onTimeout: [Function: bound checkConnections],
        _timerArgs: undefined,
        _repeat: 30000,
        _destroyed: false,
        [Symbol(refed)]: false,
        [Symbol(kHasPrimitive)]: false,
        [Symbol(asyncId)]: 10,
        [Symbol(triggerId)]: 1
      },
      [Symbol(kUniqueHeaders)]: null
    },
    parser: null,
    on: [Function (anonymous)],
    addListener: [Function (anonymous)],
    prependListener: [Function: prependListener],
    setEncoding: [Function: socketSetEncoding],
    _paused: false,
    timeout: 0,
    [Symbol(async_id_symbol)]: 58,
    [Symbol(kHandle)]: TCP {
      reading: true,
      onconnection: null,
      _consumed: true,
      [Symbol(owner_symbol)]: [Circular *2]
    },
    [Symbol(lastWriteQueueSize)]: 0,
    [Symbol(timeout)]: null,
    [Symbol(kBuffer)]: null,
    [Symbol(kBufferCb)]: null,
    [Symbol(kBufferGen)]: null,
    [Symbol(kCapture)]: false,
    [Symbol(kSetNoDelay)]: true,
    [Symbol(kSetKeepAlive)]: false,
    [Symbol(kSetKeepAliveInitialDelay)]: 0,
    [Symbol(kBytesRead)]: 0,
    [Symbol(kBytesWritten)]: 0,
    [Symbol(websocket)]: [Circular *1]
  },
  _isServer: true,
  [Symbol(kCapture)]: false
}

 

뭐 저걸 다 볼 필요는 없고, 그냥 한번 살펴보고 싶을 때 만.

 

 

 

 

그리고 마찬가지로,

const socket = new WebSocket("ws://localhost:3000");

클라이언트 쪽의 app.js 또한 소켓을 가지고 있다..

 

즉, 저걸 통해 서버와 클라이언트 서로 실시간 소통을 할 수 있다.