본 글은 다음의 자료를 참조하여 작성 하였습니다. www.slideshare.net/SangikBae/golang-websocket-109095156
서버 사이드의 코드만 작성하도록 하겠습니다.
왼쪽의 사진과 같이 총 3개의 파일로 이루어진 채팅방을 만들 계획입니다.
우선 main.go 를 살펴 보도록 하겠습니다.
func main() {
r := newRoom()
http.Handle("/room", r)
go r.run()
http.ListenAndServe(":8000",nil)
}
우선 room은 추후에 만들 코드이고, 우선은 room 이라는 것을 만들어서 실행시키는 것이 main의 모든 기능입니다.
그럼 room.go의 코드를 작성해 보도록 하겠습니다.
room 은 client의 배열을 가지는 struct 입니다.
forward 채녈은 수신한 메시지를 다른 클라이언트로 전달하고,
join은 room에 들어오려는 클라이언트를 위한 채널이고
leave는 room을 떠나는 클라이언트를 위한 채널입니다.
type room struct {
// forward는 수신 메시지를 보관하는 채널 수신한 메시지는 다른 클라이언트로 전달되어야 한다.
forward chan []byte
// join은 방에 들어오려는 클라이언트를 위한 채널이다.
join chan *client
//leave는 방을 나가길 원하는 클라이언트를 위한 채널이다.
leave chan *client
// clients는 현재 채팅방에 있는 모든 클라이언트를 보유한다.
clients map[*client]bool
}
func (r *room) run() {
for {
select {
case client := <-r.join:
//입장
r.clients[client] = true
case client := <-r.leave:
//퇴장
delete(r.clients, client)
close(client.send)
case msg := <-r.forward:
fmt.Println(string(<-r.forward))
// 모든 클라이언트에게 메시지 전달
for client := range r.clients {
client.send <- msg
}
}
}
}
const (
socketBufferSize = 1024
messageBufferSize = 256
)
var upgrader = &websocket.Upgrader{ReadBufferSize: socketBufferSize, WriteBufferSize: messageBufferSize}
func (r *room) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// upgrader.CheckOrigin = func(r *http.Request) bool { return true }
socket, err := upgrader.Upgrade(w, req, nil)
if err != nil {
log.Fatal("serveHTTP: ", err)
return
}
client := &client{
socket: socket,
send: make(chan []byte, messageBufferSize),
room: r,
}
r.join <- client
defer func() { r.leave <- client }()
go client.write()
client.read()
}
func newRoom() *room {
return &room{
forward: make(chan []byte),
join: make(chan *client),
leave: make(chan *client),
clients: make(map[*client]bool),
}
}
client.go의 코드입니다.
type client struct {
// socket은 이 클라이언트의 websocket
socket *websocket.Conn
// send는 메시지가 전송되는 체널
send chan []byte
// room은 클라이언트가 채팅하는 방
room *room
}
func (c *client) read() {
defer c.socket.Close()
for {
_, msg, err := c.socket.ReadMessage()
if err != nil {
return
}
data := db.Connect(string(msg))
fmt.Println(data)
c.room.forward <- msg
}
}
func (c *client) write() {
defer c.socket.Close()
for msg := range c.send {
err := c.socket.WriteMessage(websocket.TextMessage, msg)
if err != nil {
return
}
}
}
이해가 안가시거나 golang websocket에 대하여 궁금한 점이 있으시면 주저없이 댓글 남겨주시기 바랍니다.
감사합니다.
'프로그래밍 > golang' 카테고리의 다른 글
go colly 내가 경험한 최고의 스크래핑 프레임워크 (0) | 2021.05.24 |
---|---|
주니어 개발자의 go랭 서버 개발일지 -2 웹소켓 생성 및 읽고 쓰기 (0) | 2021.04.15 |
주니어 개발자의 go랭 서버 개발일지 -1 프로젝트 회고 (0) | 2021.04.15 |