인프런 커뮤니티 질문&답변

김동주님의 프로필 이미지
김동주

작성한 질문수

대용량 채팅 TPS 처리를 위한 웹소켓 통신 만들며 학습하기

socket message 이벤트 처리를 위한 client 함수 작성하기

채팅이 2번씩 전송되는 현상 질문

해결된 질문

작성

·

166

1

안녕하세요 go 서버 구축 이후 프론트 연결하여 채팅을 전송하면 같은 메시지가 두 번씩 전송되는 현상이 발생합니다.

강의를 여러 번 체크하면서 봤는데 소스 코드가 다른 점은 찾지 못했습니다.

 

제가 작성한 socket.go 코드인데 어떤 부분이 문제가 있을까요

package network

import (
	"chat_server_golang/types"
	"log"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
) 


var upgrader = &websocket.Upgrader{ReadBufferSize: types.SocketBufferSize, WriteBufferSize: types.MessageBufferSize,
	CheckOrigin: func(r *http.Request) bool {return true},
	} // http 요청을 websocket 통신으로 업그레이드 해준다.


type message struct {
	Name string
	Message string
	Time int64
}

type Room struct {
	Forward chan *message
	Join chan *client
	Leave chan *client

	Clients map[*client]bool
}

type client struct {
	Send chan *message
	Room *Room
	Name string
	Socket *websocket.Conn
}

func NewRoom() *Room {
	return &Room {
		Forward: make(chan *message),
		Join: make(chan *client),
		Leave: make(chan *client),
		Clients: make(map[*client]bool),
	}
}

func (c *client) Read() {
	// 클라이언트가 들어오는 멧세지를 읽는 작업
	defer c.Socket.Close()
	for {
		var msg message
		err := c.Socket.ReadJSON(&msg)
		if err != nil {
			if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
				break
			}
			panic(err)
		} else {
			log.Println("READ : ", msg, "client", c.Name)
			log.Println()

			msg.Time = time.Now().Unix()
			msg.Name = c.Name

			c.Room.Forward <- &msg
		}

		msg.Name = c.Name
		c.Room.Forward <- &msg
	}
}

func (c *client) Write() {
	// 클라이언트가 나가는 메시지를 전송하는 작업
	defer c.Socket.Close()

	for msg := range c.Send {
		log.Println("WRITE : ", msg, "client", c.Name)
		log.Println()

		err := c.Socket.WriteJSON(msg)
		if err != nil {
			panic(err)
		}	
	}
}


func (r *Room) RunInit() {
	// room 에 있는 모든 채널 값을 받는 작업
	// join leave 등의 메시지 큐를 처리, 무한반복문을 돌면서 처리
	for {
		log.Println(r.Clients)
		log.Println(r.Forward)
		select {
		case client := <-r.Join:
			r.Clients[client] = true
		case client := <-r.Leave:
			r.Clients[client] = false

			close(client.Send)

			delete(r.Clients, client)
		case msg := <-r.Forward:
			for client := range r.Clients {
				client.Send <- msg
			}
		}
	}
}

func (r *Room) SocketServe(c *gin.Context) {
	socket, err := upgrader.Upgrade(c.Writer, c.Request, nil)

	if err != nil {
		panic(err)
	}

	userCookie, err := c.Request.Cookie("auth")
	
	if err != nil {
		panic(err)
	}

	log.Println("userCookie", userCookie)

	client := &client{
		Socket: socket,
		Send: make(chan *message, types.MessageBufferSize),
		Room: r,
		Name: userCookie.Value,
	}

	r.Join <- client // 채팅방에 클라이언트가 들어왔다고 알림	

	defer func() { r.Leave <- client }() // 클라이언트가 나갔다고 알림, 클라이언트가 나가면서 defer 함수가 실행된다.

	go client.Write()
	client.Read()
}
2024/05/20 01:39:17 userCookie auth=one
2024/05/20 01:39:17 map[0x14000512600:true]
2024/05/20 01:39:17 0x14000192600
2024/05/20 01:39:21 READ :  { hi 0} client one
2024/05/20 01:39:21 
2024/05/20 01:39:21 map[0x14000512600:true]
2024/05/20 01:39:21 0x14000192600
2024/05/20 01:39:21 map[0x14000512600:true]
2024/05/20 01:39:21 0x14000192600
2024/05/20 01:39:21 WRITE :  &{one hi 1716136761} client one
2024/05/20 01:39:21 
2024/05/20 01:39:21 WRITE :  &{one hi 1716136761} client one
2024/05/20 01:39:21 

답변 1

1

July님의 프로필 이미지
July
지식공유자

안녕하세요 👋

 

메시지가 두개씩 나오는 이유로 질문을 주셨습니다.

소스를 확인해보니 의심할 부분이 보이는거 같아요.

 

Read함수를 보시면 Forward에 두번 전송을 하고 있습니다.

 

그러면 채널이 두개의 값을 전달받아 처리가 될 우려가 있어요!! 🤔🤔

 

그러니 한번의 전송만 진행하게 코드를 수정해보시면 어떨까싶네요.🎉

 

한번 진행해보시고 해결이 안된다면 다시 질문 부탁드립니다.

늦은시간까지 열심히 하시네요!! 화이팅👏

김동주님의 프로필 이미지
김동주
질문자

한 곳의 msg forward를 제거하니 정상적으로 동작했습니다. 감사합니다.

김동주님의 프로필 이미지
김동주

작성한 질문수

질문하기