[Golang] WebSocket 사용해보기
32742 단어 typescriptgo
소개
이해를 위해 Pion examples 먼저 Golang에서 WebSocket을 사용해 봅니다.
이번에는 서버 측에서 gorilla / websocket을 사용하겠습니다.
환경
기본 프로젝트
index.html
<!DOCTYPE html>
<html>
<head>
<title>Go Sample</title>
<meta charset="utf-8">
<link href="css/site.css" rel="stylesheet" />
</head>
<body>
<div id="sample_message"></div>
<textarea id="input_message"></textarea>
<button onclick="Page.connect('{{.}}')">Connect</button>
<button onclick="Page.send()">Send</button>
<button onclick="Page.close()">Close</button>
<div id="received_text_area"></div>
<script src="js/main.page.js"></script>
</body>
</html>
main.page.ts
import { WebsocketMessage } from "./websocket.type";
let ws: WebSocket|null = null;
export function connect(url: string): void {
ws = new WebSocket(url);
ws.onopen = () => sendMessage({
messageType: "text",
data: "connected",
});
ws.onmessage = data => {
const message = <WebsocketMessage>JSON.parse(data.data);
switch(message.messageType) {
case "text":
if(typeof message.data === "string") {
addReceivedMessage(message.data);
} else {
console.error(message.data);
}
break;
default:
console.log(data);
break;
}
};
}
export function send() {
const messageArea = document.getElementById("input_message") as HTMLTextAreaElement;
sendMessage({
messageType: "text",
data: messageArea.value,
});
}
export function close() {
if(ws == null) {
return;
}
ws.close();
ws = null;
}
function addReceivedMessage(message: string) {
const receivedMessageArea = document.getElementById("received_text_area") as HTMLElement;
const child = document.createElement("div");
child.textContent = message;
receivedMessageArea.appendChild(child);
}
function sendMessage(message: WebsocketMessage) {
if (ws == null) {
return;
}
ws.send(JSON.stringify(message));
}
websocket.type.ts
export type WebsocketMessage = {
messageType: "text"
data: string|Blob|ArrayBuffer,
};
main.go
package main
import (
"html/template"
"log"
"net/http"
"path/filepath"
"sync"
)
type templateHandler struct {
once sync.Once
filename string
templ *template.Template
}
func (t *templateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
t.once.Do(func() {
t.templ = template.Must(template.ParseFiles(filepath.Join("templates", t.filename)))
})
t.templ.Execute(w, "Hello world")
}
func main() {
http.Handle("/css/", http.FileServer(http.Dir("templates")))
http.Handle("/js/", http.FileServer(http.Dir("templates")))
http.HandleFunc("/websocket", websocketHandler)
http.Handle("/", &templateHandler{filename: "index.html"})
log.Fatal(http.ListenAndServe("localhost:8080", nil))
}
WebSocket을 통해 내 자신의 메시지 수신 및 전송
룸고
package main
import (
"encoding/json"
"log"
"net/http"
"strconv"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
type websocketMessage struct {
MessageType string `json:"messageType"`
Data string `json:"data"`
}
func websocketHandler(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println(err)
return
}
// Close the connection when the for-loop operation is finished.
defer conn.Close()
message := &websocketMessage{}
for {
// the first message is "connected"
messageType, raw, err := conn.ReadMessage()
if err != nil {
log.Println(err)
return
} else if err := json.Unmarshal(raw, &message); err != nil {
log.Println(err)
return
}
conn.WriteJSON(message)
}
}
업그레이드
WebSocket 연결을 설정하려면 설정된 연결의 프로토콜을 HTTP/1.1에서 WebSocket으로 변경해야 합니다.
클라이언트 측의 WebSocket API는 WebSocket 관련 헤더를 추가합니다.
요청 헤더(Google Chrome)
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,ja-JP;q=0.8,ja;q=0.7,zh-CN;q=0.6,zh;q=0.5
Cache-Control: no-cache
Connection: Upgrade
Host: localhost:8080
Origin: http://localhost:8080
Pragma: no-cache
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Key: loDo1/V2L+3izvedjmEt9A==
Sec-WebSocket-Version: 13
Upgrade: websocket
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36
"websocket.Upgrader.Upgrade"는 요청 헤더를 검사하여 새로운 연결(net.Conn)을 생성하고 연결을 이어받을 수 있도록 합니다.
룸고
...
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
...
func websocketHandler(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
...
}
연결 후 아래와 같은 응답 헤더를 얻을 수 있습니다.
응답 헤더
Connection: Upgrade
Sec-WebSocket-Accept: /CQqmm5VOeDDGblpvMXlK56DWFs=
Upgrade: websocket
연결 관리
다른 유저들과 대화를 하려면 .
연결을 유지하기 위한 공통 사양이 없기 때문에 모든 샘플은 이를 다른 방식으로 구현합니다.
예를 들어 sfu-ws of Pion example은 PeerConnection과의 연결을 유지합니다.
액세스할 때 먼저 잠급니다.
반면 Chat Example of gorilla/websocket은 하나의 "허브"인스턴스를 생성하고 여기에 연결을 설정합니다.
이번에는 Pion 예제와 같은 연결을 유지합니다.
룸고
package main
import (
"encoding/json"
"log"
"net/http"
"sync"
"github.com/gorilla/websocket"
)
var (
upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
listLock sync.RWMutex
connections []connectionState
)
type websocketMessage struct {
MessageType string `json:"messageType"`
Data string `json:"data"`
}
type connectionState struct {
websocket *threadSafeWriter
}
type threadSafeWriter struct {
*websocket.Conn
sync.Mutex
}
func websocketHandler(w http.ResponseWriter, r *http.Request) {
unsafeConn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println(err)
return
}
conn := &threadSafeWriter{unsafeConn, sync.Mutex{}}
// Close the connection when the for-loop operation is finished.
defer conn.Close()
listLock.Lock()
connections = append(connections, connectionState{websocket: conn})
listLock.Unlock()
message := &websocketMessage{}
for {
_, raw, err := conn.ReadMessage()
if err != nil {
log.Println(err)
return
} else if err := json.Unmarshal(raw, &message); err != nil {
log.Println(err)
return
}
for _, c := range connections {
c.websocket.WriteJSON(message)
}
}
}
func (t *threadSafeWriter) WriteJSON(v interface{}) error {
t.Lock()
defer t.Unlock()
return t.Conn.WriteJSON(v)
}
자원
Reference
이 문제에 관하여([Golang] WebSocket 사용해보기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/masanori_msl/golang-try-websocket-1ghm텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)