LoginSignup
0
1

More than 3 years have passed since last update.

WebSocket メモ

Last updated at Posted at 2020-11-25

WebSocket とは

  • クライアントとリモートホストの間で双方向通信を可能とするプロトコル。
  • セキュリティモデルはウェブブラウザでよく用いられるオリジンをベースとしたモデル。
  • XMLHttpRequest やロングポーリングに頼らずにサーバとの双方向通信を必要とするブラウザアプリケーションのためのメカニズムを提供する。
  • クライアント・サーバ間の双方向のトラフィックのためにTCPコネクションを一つだけ張る。

プロトコルの概要

プロトコルはハンドシェイクデータ転送の2つの部分からなる。

ハンドシェイク

クライアント -> サーバ

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

サーバ -> クライアント

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat

ハンドシェイクが成功すると、クライアントとサーバは1つ以上のフレームからなるメッセージをお互いに送出し合うことになる。

Node.js でシンプルな WebSocket 通信

Node.js では、ws というWebSocketライブラリを用いてシンプルな WebSocket 通信ができる(Socket.IO でも可能)。

サーバ側のコード

const WebSocket = require('ws')

const server = new WebSocket.Server({ port: 3000 })

server.on('connection', ws => {
  ws.send('connected!')

  ws.on('message', message => {
    console.log('received: %s', message)
  })
})

クライアント側のコード

const ws = require('ws')

const client = new ws('ws://localhost:3000')

client.on('open', () => {
  client.send('hello')
})

client.on('message', message => {
  console.log(message)
})

node server.js でWebSocketサーバを立ち上げた後 node client.js を実行すると、サーバ側では

received: hello

と出力され、クライアント側では

connected!

と出力される。

WebSocket でチャットアプリを作る

blessed というクールな CUI を作れるライブラリを使って、超シンプルなチャットアプリ(もどき)を作ってみる。

サーバ側

const WebSocket = require('ws')

const server = new WebSocket.Server({ port: 3000 })

const sockets = new Map()

const broadcast = message => {
  console.log(message)
  server.clients.forEach(client => {
    if (client.readyState === WebSocket.OPEN) {
      client.send(message)
    }
  })
}

server.on('connection', socket => {
  socket.on('message', message => {

    if (sockets.has(socket)) {
      const name = sockets.get(socket)
      broadcast(`${name}: ${message}`)
    } else {
      sockets.set(socket, message)
      broadcast(`${message} entered the room.`)
    }
  })

  socket.on('close', () => {
    const name = sockets.get(socket)
    if (name) {
      sockets.delete(socket)
      broadcast(`${name} left the room.`)
    }
  })
})

クライアント側

const ws = require('ws')
const blessed = require('blessed')

const screen = blessed.screen({ smartCSR: true })
screen.title = 'chat'

const chatList = blessed.list({ border: { type: 'line' } })

const textbox = blessed.textbox({
  height: '10%',
  bottom: 0,
  input: true,
  inputOnFocus: true,
  border: {
    type: 'line'
  }
})

const client = new ws('ws://localhost:3000')

client.on('open', async () => {
  textbox.setText('(Please enter your name)')
  textbox.focus()
  screen.render()
})

client.on('message', message => {
  chatList.insertLine(0, message)
  screen.render()
})

textbox.key(['enter'], () => {
  client.send(textbox.getText())
  textbox.clearValue()
  chatList.render()
  textbox.focus()
})


const EXIT_COMMANDS = ['escape', 'C-c']
const exit = () => process.exit(0)
screen.key(EXIT_COMMANDS, exit)
chatList.key(EXIT_COMMANDS, exit)
textbox.key(EXIT_COMMANDS, exit)


screen.append(chatList)
screen.append(textbox)
screen.render()

実際の動作

chat.gif

それっぽくは動く。

所感

  • blessed の API がよくわからない
  • ブラウザを UI としたチャットアプリを作ってみたい
  • 随時更新する

出典

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1