본문 바로가기

프로그래밍/golang

주니어 개발자의 golang 서버 개발일지 -3 웹소켓을 이용한 채팅방 만들기.

 본 글은 다음의 자료를 참조하여 작성 하였습니다. 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에 대하여 궁금한 점이 있으시면 주저없이 댓글 남겨주시기 바랍니다. 

 

감사합니다.