피드로 돌아가기
Building a Concurrent TCP Chat Server in Go (NetCat Clone)
Dev.toDev.to
Backend

Building a Concurrent TCP Chat Server in Go (NetCat Clone)

Go 프로젝트가 Goroutine과 Channel 기반의 중앙 집중식 이벤트 루프로 다중 TCP 클라이언트의 공유 상태 관리 문제 해결

Valery Odinga2026년 3월 24일8intermediate

Context

다중 클라이언트가 동시에 연결될 때 공유 데이터(클라이언트 맵, 메시지 히스토리)에 대한 동시 접근으로 인한 레이스 컨디션과 충돌("fatal error: concurrent map writes")이 발생했습니다. 뮤텍스 기반 해결책은 데드락 가능성과 성능 병목을 야기했습니다.

Technical Solution

  • ChatRoom 구조체 도입: Register, Unregister, Broadcast 채널을 통해 상태 변경 이벤트를 단일 고루틴으로 직렬화
  • Run() 메서드의 select 루프: 세 채널에서 들어오는 이벤트를 순차 처리하여 공유 상태에 대한 동시 접근 제거
  • 클라이언트별 독립 고루틴: 각 연결을 go handleConnection(conn)으로 분리하여 느린 클라이언트가 다른 클라이언트를 블로킹하지 않도록 구성
  • 메시지 브로드캐스트 로직: cr.chatters 맵을 순회하며 발신자를 제외한 각 클라이언트의 receive 채널로 메시지 전송
  • 에러 핸들링: ReadString() 반환값으로 io.EOF 감지하여 클라이언트 종료 감지 및 Unregister 채널로 통지

Key Takeaway

Go의 "메모리를 공유하지 말고 메모리를 통신으로 공유하라"는 철학에 따라 뮤텍스 대신 채널 기반의 단일 소유권 패턴을 적용하면 동시성 관련 버그를 원천적으로 제거하고 코드 복잡도를 낮출 수 있습니다.


Go로 다중 클라이언트 실시간 통신 시스템을 구축할 때, 공유 자료구조를 중앙 고루틴 하나가 소유하고 모든 상태 변경을 채널 이벤트로 전달받는 액터 패턴을 적용하면 뮤텍스 기반 대비 레이스 컨디션을 완전히 제거하고 버그 디버깅 시간을 단축할 수 있습니다.

원문 읽기
Building a Concurrent TCP Chat Server in Go (NetCat Clone) | Devpick