[프로젝트 김필여 - 8일차] 대규모 동시접속 TCP C# 서버 제작기

2023. 10. 11. 15:21· Side Project/안양시장 프로젝트 - TCP 서버개발
목차
  1. 프로젝트 Git Hub Repository 링크
  2. 이전 포스트
  3. 지금 해결하고 싶은 문제점
  4. exit 입력 시 연결 종료 에러를 없애기
  5. Shutdown 와 Disconnect의 차이점
  6. 하지만 여전히 에러가 발생합니다.
신입 개발자가 작성한 연구일지입니다. 이때 오해하고 있던 잘못된 정보가 포함되어 있습니다.

목표

30000명이 동시에 접속할 수 있는 TCP 서버 만들기
30000명의 클라이언트는 전송 - 수신 - 전송 - 수신 을 반복한다.
30000명의 클라이언트를 켜 놓고, 다음날 서버가 에러 없이 살아 있는 것을 목표한다.
목표를 성취한 후에는 평균 응답 시간을 줄여보도록 하겠다.

프로젝트 Git Hub Repository 링크

https://github.com/MatorMirne/SocketCommunicate-TCP

이전 포스트

  • 1일차 : 2023.06.26 - [일지/C#] - [프로젝트 예수 - 1일차] 대규모 동시접속 TCP 서버
  • 2일차 : 2023.06.27 - [일지/C#] - [프로젝트 예수 - 2일차] 대규모 동시접속 TCP 서버 제작기
  • 3일차 : 2023.06.28 - [일지/C#] - [프로젝트 김필여 - 3일차] 대규모 동시접속 TCP C# 서버 제작기
  • 4일차 : 2023.06.29 - [일지/미니프로젝트] - [프로젝트 김필여 - 4일차] 대규모 동시접속 TCP C# 서버 제작기
  • 5일차 : 2023.07.05 - [일지/미니프로젝트] - [프로젝트 김필여 - 5일차] 대규모 동시접속 TCP C# 서버 제작기
  • 6일차 : 2023.07.24 - [일지/미니프로젝트] - [프로젝트 김필여 - 6일차] 대규모 동시접속 TCP C# 서버 제작기
  • 7일차 : 2023.07.25 - [일지/미니프로젝트] - [프로젝트 김필여 - 7일차] 대규모 동시접속 TCP C# 서버 제작기

 

하하 오랜만에 필을 업데이트 해 주네요 비동기 공부를 조~금 더 하고 돌아왔습니다.

2023.08.08 - [일지/C#] - 내가 생각한 비동기 입력은 없었다

공부 내용은 위 링크에서 확인할 수 있습니다!

확실한 지식은 아닌 것 같지만 ㅠㅠ 제 연구일지를 보실 수 있습니다.

지금은 이 글을 이해하려고 노력해보고 있습니다. 저는 언제쯤 비동기를 정복할 수 있을까요 ...

 

지금 해결하고 싶은 문제점

지금까지 TCP 연결 해제를 아래 코드로 하고 있었습니다.

한 마디로 설명하자면, 버퍼에  "" 가 입력되면 종료를 하는 방식이었습니다.

위와 같은 방식은 정말로 ""가 입력되었을 때에도 종료된다는 문제점이 있고, 프로그램이 정상 종료되지 않았을 때에도 문제가 발생하는 것으로 보입니다.

 

사실 웬만한 기능들이 잘 작동되고 있기 때문에 😭 모른척하려 애썼습니다 ㅋㅋㅋ (나는 못봤다... 나는 못봤다...)

하지만 저번 포스트에서도 언급한 문제가 발생했고, 더 이상은 모른척 할 수 없을 것 같습니다!

 

1. 우선 exit 입력 시 연결 종료 에러를 없애 보고

2. 그 다음엔 비정상 종료시 연결 종료 에러를 없애 보겠습니다.

 

 

현재 발생하고 있는 문제점

 

exit 입력 시 연결 종료 에러를 없애기

현재 에러 로그 내용은 이렇습니다.

Unhandled exception. System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.Socket'.
   at System.Net.Sockets.Socket.ReceiveAsync(SocketAsyncEventArgs e, CancellationToken cancellationToken)
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ReceiveAsync(Socket socket, CancellationToken cancellationToken)
   at System.Net.Sockets.Socket.ReceiveAsync(ArraySegment`1 buffer)
   at TCPClient.Client.WorkAsync() in /Users/jaeeun/free/SocketCommunicate-TCP/TCPClient/TCPClient/Client.cs:line 46
   at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_1(Object state)
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
   at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()
   at System.Threading.Thread.StartCallback()

에러 내용을 읽어 보니 이미 dispose 된 객체에 46번 라인이 입력된 것 같습니다.

 

 

문제의 46번 라인의 코드는 이것입니다.

            var length = await socket.ReceiveAsync(receiveBuffer);

 

 

저는 지금까지 소켓의 연결 종료를 Shutdown() 함수를 통해 구현하고 있었습니다.

저는 이 코드를 Disconnect 로 변경했습니다.

 

 

Shutdown 와 Disconnect의 차이점

출처: https://ckbcorp.tistory.com/887

출처: https://learn.microsoft.com/ko-kr/dotnet/api/system.net.sockets.socket.disconnect?view=net-7.0 

 

Shutdown은 바로 끊는 것이고, Disconnect는 송수신중인 데이터의 송수신이 완료된 후 작업이 끊긴다고 합니다.

 

 

하지만 여전히 에러가 발생합니다.

에러 내용이 조금 바뀐 채로 에러가 발생하고 있습니다.

Unhandled exception. System.Net.Sockets.SocketException (89): Operation canceled
   at System.Net.Sockets.SocketAsyncContext.ReceiveAsync(Memory`1 buffer, SocketFlags flags, Int32& bytesReceived, Action`5 callback, CancellationToken cancellationToken)
   at System.Net.Sockets.SocketAsyncEventArgs.DoOperationReceive(SafeSocketHandle handle, CancellationToken cancellationToken)
   at System.Net.Sockets.Socket.ReceiveAsync(SocketAsyncEventArgs e, CancellationToken cancellationToken)
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ReceiveAsync(Socket socket, CancellationToken cancellationToken)
   at System.Net.Sockets.Socket.ReceiveAsync(ArraySegment`1 buffer)
   at TCPClient.Client.WorkAsync() in /Users/jaeeun/free/SocketCommunicate-TCP/TCPClient/TCPClient/Client.cs:line 46
   at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_1(Object state)
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
   at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()
   at System.Threading.Thread.StartCallback()

에러 내용을 읽어 보니, 46번 라인 요청을 하던 중 요청이 중도 취소된 것 같습니다.

최최최후의 보루로, try catch 문을 넣어 에러가 나지 않게 46번 줄을 보호하는 방법도 있지만, 분명 MS 개발자 분들이 개발해 둔 메서드가 있을 텐데요 ...

 

그런데 문득 이런 생각이 듭니다.

카카오톡 보낸 메세지 삭제 기능이 없던 시절, 저는 실수로 카카오톡을 보냈을 때면 재빨리 와이파이를 꺼 버리곤 했습니다.

제가 만드는 채팅 서버 또한 카카오톡과 같은 기능을 하니, 이런 경우에서 어떻게 메세지를 처리할지는 제 재량이 아닐까요 ?!

 

아 아니구나 46번은 받는거구나.

받는 걸 취소해버리면 문제가 생길 것 같습니다.

메세지를 받는 과정에서 프로그램 종류 에러가 있었다면, 해당 메세지를 다 받은 후에 안전하게 종료해야 할 것 같습니다.

 

지금 드는 의문은 저 에러가 단순히 ReceiveAsync 를 호출 했는데, 중단되었다는 것인지

무언가 데이터를 받는 중에 중단되었다는 것인지이다.

 

만약 전자라면 그냥 try catch 로 처리하면 될 것이고, 후자라면 별도의 조치가 필요할 것이다.

 

오! 이를 실험하기 위해서는 Server의 전송부를 없애 보면 될 것 같다!

확인해 보니, 아무것도 보내지 않아도 이와 같은 오류가 발생했다. 단순히 ReadAsync 가 완수되지 않은 상태로 종료되어 발생하는 오류인 것으로 보인다. 여전히 무언가 보내는 중에 오류가 발생하는지에 대한 의문은 해결되지 않았지만...

당장 에러를 해결하고 이 문제부터 해결한 후에 다시 생각해보도록 하겠습니다.

 

그러다 보니 예외 처리가 너무 많아졌네요 .... 이렇게 하면 되긴 합니다. 그런데 마음이 너무 불편합니다 ㅠㅠ 더 좋은게 분명 있을텐데 말입니다.

 

 

 

 

 

더 이상 혼자 삽질은 그만하고, Best Case 를 구글링해보도록 하겠습니다.

 

공식 MS 홈페이지에서는 이런 방식으로 연결을 해제를 감지하고 있습니다.

https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.tcplistener?view=net-7.0 

받은 데이터의 길이가 0이면 연결을 종료합니다.

위와 같은 방식으로 프로그램을 만들면, 전송을 잠시 대기할 때에도 전송하는 데이터는 0개이므로 연결이 종료될 위험이 있는 것 같습니다. 

 

 

 

 

 

 

아래 코드를 참고해서 확인해 보니

https://github.com/davidfowl/TcpEcho/blob/master/src/Server/Program.cs

 

오호 이런 함수가 있네요 ! 바로 사용해줍니다.

 

 

 

 

 

제가 찾아본 예제에서는 전부 length가 0이면 연결을 종료하고 있습니다...

왜일까요?

 

정말로 보낸 데이터가 "" 인 경우에 연결을 종료해버리면 어쩌죠?

 

"" 데이터를 Send하도록 테스트해 보았습니다.

 

그런데 놀랍게도! 데이터가 받아지지 않았습니다!

 

 

공백 데이터를 보내면 송신 버퍼에서 무시하는것 같습니다 !

디버깅도 여러번 안잡히는 것을 확인할 수 있었습니다.

 

 

 

ms 공식 문서에서도, 구글링에서도 "" 를  Send 할 수 있는지 찾지 못했습니다.

따라서 스택오버플로우에 질문을 남겨 보았습니다.

https://stackoverflow.com/questions/77270574/c-can-socket-sendasync-send-null-stream

 

(c#) Can Socket.SendAsync send null("") stream?

First of all, sorry to my poor English ability ... My server's disconnect detection method is following code. string receiveMessage = System.Text.Encoding.UTF8.GetString(receiveBuffer, 0, length);...

stackoverflow.com

 

답변이 달리면 계속 작성해보도록 하겠습니다 !

 

지금까지의 결론은 

어짜피 ""는 전송되지 않으므로
"" 가 전송되면 or 전송받은 버퍼 크기가
0이면 종료 신호로 인지해도 될 것 같다!

입니다.

 

 

 

 

 

 

==추가==

위와 같이 코딩할 경우, 클라이언트를 강제 종료하는 경우에는 연결 종료를 위한 시그널을 보내지 않습니다.

따라서 구글링한 결과, 프로그램이 비정상 종료하는 상황에 대응하는 코드를 발견했습니다.

public static void Main(string[] args)
{
    // MyStopWatch.Start();

    Console.CancelKeyPress += OnCancelKeyPress;
}

private static void OnCancelKeyPress(object sender, EventArgs e)
{
    Console.WriteLine("클라이언트 종료");
    foreach (var client in clients)
    {
        client.Disconnect();
    }
}

위와 같이 추가하면 비정상 종료 시에도 클라이언트를 종료할 수 있었습니다 !

 

 

==추가==

상사분들께 물어보니, 대부분의 TCP 서버가 받은 데이터가 0이면 연결을 종료하도록 한다 하네요.

그리고 스택오버플로에 답글이 달렸는데, 타임오버로 인한 에러 전송 시에 length=0 인 데이터를 보내서 더욱 연결 종료 처리를 해야 한다고 하는것 같습니다.

출처가 없어서 아쉬울 따름입니다 ㅠ_ㅠ

'Side Project > 안양시장 프로젝트 - TCP 서버개발' 카테고리의 다른 글

[프로젝트 김필여 - 10일차] 대규모 동시접속 TCP C# 서버 제작기  (0) 2023.10.13
[프로젝트 김필여 - 9일차] 대규모 동시접속 TCP C# 서버 제작기  (0) 2023.10.11
[프로젝트 김필여 - 7일차] 대규모 동시접속 TCP C# 서버 제작기  (0) 2023.07.25
[프로젝트 김필여 - 6일차] 대규모 동시접속 TCP C# 서버 제작기  (0) 2023.07.24
[프로젝트 김필여 - 5일차] 대규모 동시접속 TCP C# 서버 제작기  (0) 2023.07.05
  1. 프로젝트 Git Hub Repository 링크
  2. 이전 포스트
  3. 지금 해결하고 싶은 문제점
  4. exit 입력 시 연결 종료 에러를 없애기
  5. Shutdown 와 Disconnect의 차이점
  6. 하지만 여전히 에러가 발생합니다.
'Side Project/안양시장 프로젝트 - TCP 서버개발' 카테고리의 다른 글
  • [프로젝트 김필여 - 10일차] 대규모 동시접속 TCP C# 서버 제작기
  • [프로젝트 김필여 - 9일차] 대규모 동시접속 TCP C# 서버 제작기
  • [프로젝트 김필여 - 7일차] 대규모 동시접속 TCP C# 서버 제작기
  • [프로젝트 김필여 - 6일차] 대규모 동시접속 TCP C# 서버 제작기
개발자 재은
개발자 재은
개발자 재은개발자 재은 님의 블로그입니다.
개발자 재은
개발자 재은
개발자 재은
전체
오늘
어제
  • 분류 전체보기 (72)
    • Client (5)
      • MSW (5)
    • Server (25)
      • AWS (2)
      • C# (15)
      • C# 비동기와의 전쟁 (5)
      • Linux (3)
      • MySQL (0)
      • Orleans(정리안됨) (0)
    • Error Note (2)
    • Side Project (15)
      • 안양시장 프로젝트 - TCP 서버개발 (15)
    • 일지 (25)
      • 일기장 (16)
      • 2022 MSW 해커톤 대상 후기 (5)
      • 자기소개 (0)
      • 미완성 포스트 (1)
      • 넥토리얼 합격 회고 (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

최근 댓글

최근 글

hELLO · Designed By 정상우.v4.2.1
개발자 재은
[프로젝트 김필여 - 8일차] 대규모 동시접속 TCP C# 서버 제작기
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.