inflearn logo
강의

Khóa học

Chia sẻ kiến thức

Học cách xây dựng giao tiếp WebSocket để xử lý TPS chat lớn

Viết hàm máy khách để xử lý các sự kiện thông báo ổ cắm

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

Đã giải quyết

314

harhyom91896752

1 câu hỏi đã được viết

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 

go websockets

Câu trả lời 1

1

July

안녕하세요 👋

 

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

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

 

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

 

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

 

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

 

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

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

1

harhyom91896752

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

gRPC 실무에서 질문

0

35

2

교안에 사용되는 app.js 파일은 어디서 받을수 있을까요?

0

43

1

소스 download

0

43

2

프로젝트 구조 관련 질문이 있습니다.

0

48

1

커넥션 min, max 설정과 관련하여

0

50

1

명령어 오류가 있으신 분들 저는 이렇게 해결했어요!

0

70

1

Streaming 중인 서비스에서 모든 파드에 broadcast하는 방법

0

119

3

프론트쪽이 리액트로 되어있는데요..

0

124

2

오늘 강의 듣기 시작했는데요!

0

132

2

RunInit() 관련 질문

0

181

5

소켓 연결과 http

0

154

2

학습자료는 어디서 받나요?

1

200

1

현재 강의에서 재생관련 문제가 있어서 전달드립니다.

1

202

2

강의에 음성만 나오고 영상이 나오질 않습니다 ㅠ

0

142

1

데이터 불러오기

1

143

1

panic 사용

1

116

1

defer 사용

1

129

1

nodejs 파일이 프론트엔디 파일인가요??

0

221

1

채팅 메시지 DB로 저장 하기.

1

843

2

뭔가 중간에 오타를 쳤는지 오류가 자꾸 발생하는데 혹시 go 소스코드 볼수있는곳 있나요?

1

247

1

다른 질문을 읽고 궁금한 점이 생겼습니다.

1

303

1

소켓 서버의 수평적 확장 및 무중단 배포에 대해 질문드립니다!

3

1306

2

app.js를 여러 번 실행했음에도 불구하고, 로그가 단 한 번만 출력됨

1

336

2

몇천명이 Room 에 동시접속할 수 있도록 설계하려면 어떤 것들이 필요할까요?

1

473

2