이번 포스팅에서는 대규모 동시 접속을 지원하는 서버를 만드는 테스트 프로젝트를 진행하며, 과정에 대해 적어 보려 합니다.
목표
30000명이 동시에 접속할 수 있는 TCP 서버 만들기
30000명의 클라이언트는 전송 - 수신 - 전송 - 수신 을 반복한다.
30000명의 클라이언트를 켜 놓고, 다음날 서버가 에러 없이 살아 있는 것을 목표한다.
목표를 성취한 후에는 평균 응답 시간을 줄여보도록 하겠다.
프로젝트 Git Hub Repository 링크
https://github.com/MatorMirne/SocketCommunicate-TCP
프로젝트 명명 - 프로젝트:예수
저는 프로젝트에 이름 붙이기를 좋아합니다. 그렇게 하면 더 프로그램에 애정을 가질 수 있기 때문입니다.
(저는 무교입니다!) 성경 말씀에 예수는 모두를 포용한다 그러지요.
이번 프로젝트의 목표는 여러 클라이언트 포용이므로, 명명으로 예수가 딱인것 같습니다. (내 예수는 3만명만 포용하지만...)
기본 소켓 통신
우선 TCP 프로토콜을 사용하는 소켓을 만들어 보았습니다.
코드 보기 - 링크(클릭)
아직까지는 코드가 짧으므로 전문을 첨부해 보도록 하겠습니다.
// 서버 Main문
// 1. local 환경에서 연결하므로 IP 주소는 127.0.0.1 으로 설정하였습니다.
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint endPoint = new IPEndPoint(ipAddress, 51225);
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 2. 소켓을 Bind - Listen - Accept 하여 연결을 설정했습니다.
serverSocket.Bind(endPoint);
serverSocket.Listen(10); // 추후 3만으로 업그레이드
Socket clientSocket = serverSocket.Accept(); // 저장된 소켓 정보를 반환
// 데이터가 올때까지 대기
// 3. 데이터를 수신하였습니다.
byte[] receiveBuffer = new byte[1024];
int length = clientSocket.Receive(receiveBuffer, 0, 1024, SocketFlags.None);
string receiveMessage = System.Text.Encoding.UTF8.GetString(receiveBuffer, 0, length);
Console.WriteLine(receiveMessage);
// 4. 받은 데이터에서 수를 +1 하여 전송해 주었습니다.
string sendMessage = (int.Parse(receiveMessage) + 1).ToString();
byte[] sendBuffer = System.Text.Encoding.UTF8.GetBytes(sendMessage);
clientSocket.Send(sendBuffer, 0, sendMessage.Length, SocketFlags.None);
Console.WriteLine(sendMessage);
// 5. 발행한 소켓을 해제해 주었습니다.
clientSocket.Close();
serverSocket.Close();
// 클라이언트 Main문
// 1. 마찬가지로 local IP 에 연결하도록 했습니다.
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint endPoint = new IPEndPoint(ipAddress, 51225);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 2. Listen 중인 서버에 소켓을 연결했습니다.
socket.Connect(endPoint);
// 3. 데이터를 전송합니다.
string message = "1";
byte[] sendBuffer = System.Text.Encoding.UTF8.GetBytes(message);
socket.Send(sendBuffer);
// 4. 답신을 받아 출력합니다.
byte[] receiveBuffer = new byte[1024];
int receiveSize = socket.Receive(receiveBuffer);
string receiveMessage = System.Text.Encoding.UTF8.GetString(receiveBuffer, 0, receiveSize);
Console.WriteLine(receiveMessage);
// 5. 사용된 소켓을 반환합니다.
socket.Close();
그런데, 이상한 부분이 있었습니다. 클라이언트에서 하나의 소켓으로 Send 와 Receive 모두를 수행하는 것을 본 저는, Server도 소켓을 하나만 사용하도록 바꾸려 했습니다. 하지만 결과는 실패였습니다. 서버측의 소켓을 하나로 만들자, 이상하게도 연결이 설정되지 않았습니다. 그 이유는 바로 TCP 다중화 때문이었습니다. 만약 통신을 하기 위해 서버 컴퓨터의 51225번 포트 단 하나만을 사용한다면 어떤 일이 발생할까요?
위 그림처럼 그 서버는 하나의 클라이언트만 사용할 수 있는 속 좁은 서버가 될 것입니다. 접속은 단 한 명만이 할 수 있겠죠. 이에 따라 Listen(10) 처럼 10명이 접속할 수 있는 포트라면, 연결이 된 클라이언트는 다른 포트로 연결됩니다.
분명 대학 시절 <컴퓨터네트워크> 과목을 수강하며 배웠던 기억이 있는데, 실제로 마주치니 아주 당혹스럽습니다. 이러한 이유 때문에 서버는 연결용 포트와 연결된 클라이언트 포트를 나누어 가지고 있어야 하므로 소켓이 코드에 두 개 존재해야 했던 것입니다.
그리고, 조금 더 코드의 순서와 언제 대기가 발생하는지에 대해 자세히 살펴 보도록 하겠습니다. 저는 처음에는 왼쪽처럼 생각했으나, 우측이 맞는 그림이라는 것을 알게 되었습니다. Listen() 메서드는 마치 대기할 것 처럼 생겼지만, 사실 정말로 클라이언트를 기다리고 있는 메서드는 Accept() 입니다. 따라서 서적에는 Listen 메서드가 호출된 상태인 서버에만 Connect() 를 할 수 있다고 했지만, 정확히는 Accept() 가 실행되어 대기 중인 서버에 Connect를 수행할 수 있다는 것이 맞는 표현입니다.
>> 다음 일지 : 2023.06.27 - [일지/C#] - [프로젝트 예수 - 2일차] 대규모 동시접속 TCP 서버 제작기
[프로젝트 예수 - 2일차] 대규모 동시접속 TCP 서버 제작기
이전 포스트 바로가기 - 1일차 : 2023.06.26 - [일지/C#] - [프로젝트 예수 - 1일차] 대규모 동시접속 TCP 서버 [프로젝트 예수 - 1일차] 대규모 동시접속 TCP 서버 이번 포스팅에서는 대규모 동시 접속을
develop-jen.tistory.com
'Side Project > 안양시장 프로젝트 - TCP 서버개발' 카테고리의 다른 글
[프로젝트 김필여 - 6일차] 대규모 동시접속 TCP C# 서버 제작기 (0) | 2023.07.24 |
---|---|
[프로젝트 김필여 - 5일차] 대규모 동시접속 TCP C# 서버 제작기 (0) | 2023.07.05 |
[프로젝트 김필여 - 4일차] 대규모 동시접속 TCP C# 서버 제작기 (0) | 2023.06.29 |
[프로젝트 김필여 - 3일차] 대규모 동시접속 TCP C# 서버 제작기 (0) | 2023.06.28 |
[프로젝트 예수 - 2일차] 대규모 동시접속 TCP C# 서버 제작기 (0) | 2023.06.27 |