Home

Published

- 2 min read

RTSP connection 트러블 슈팅

img of RTSP connection 트러블 슈팅

문제 파악

회사 프로젝트 중, 지도 화면 위에서 실시간 영상을 보여주는 게 있는데 플레이어 쪽에서 Camera 드롭다운을 막 변경하다 보면 RTP 서버에 물린 RTSP 연결이 끊어지지 않고 계속 남아있는 문제가 있었다.

구성은 웹서버 & API 서버 & 미디어 서버 & RTP 서버 & 장치 이렇게 있다. 처음에는 프론트 측에서 WebRTC를 안끊어서 미디어 서버가 RTSP 연결을 유지하는 줄 알았는데 로그를 보니 그게 아니었다. WebRTC 연결이 끊어졌는데 RTSP 연결이 여전히 살아있었음.

원인

gin.Context를 handler 내의 고루틴에서 그대로 쓰고 있던게 문제였다. 예를 들어,

func handler(c *gin.Context) {
    go func() {
        // Accessing c.Param inside a goroutine
        fmt.Println("UUID:", c.Param("uuid"))
    }()
}

이런 코드가 문제다.

gin.Context는 항상 만들어지지 않는다.

아래는 gin의 실제 구현코드이다.

// ServeHTTP conforms to the http.Handler interface.
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    c := engine.pool.Get().(*Context)
    c.writermem.reset(w)
    c.Request = req
    c.reset()

    engine.handleHTTPRequest(c)

    engine.pool.Put(c)
}

여기서 engint.pool.Put(c) 로 이미 context가 풀에 반환되어있는데 동일한 참조값을 특정 고루틴에서 쓰고 있으면 race condition이 발생한다.

해결 방안

해결은 쉽다. 깊게 복사하던가 새로 하나 변수 만들면 된다. 예를 들어,

copiedContext := c.Copy()
go func() {
  do something
}()
deviceId := c.Param("guid")
go func() {
  do something
}()