[게임 서버] SetBuffer를 RecvBuffer, SendBuffer로 따로 빼내기 #2
·
공부/게임 서버
지난 게시글에서는 RecvBuffer를 만들었다. 이번에는 SendBuffer를 만들어 따로 빼내보겠다. SendBuffer는 크게 두 클래스로 나뉜다. SendBufferHelper와 SendBuffer다. SendBufferHelper 먼저 살펴보자. // ThreadLocal == 전역은 전역 변순데 내 스레드에서만 사용할 수 있는 전역변수 public static ThreadLocal CurrentBuffer = new ThreadLocal(() => { return null; }); // 그냥 사이즈가 아니라 되게 큰 뭉탱이 Size. 여기서 필요한 만큼 뽑아다 쓸 예정. public static int ChunkSize { get; set; } = 4096 * 100; 멀티 스레드 환경에서도 ..
[게임 서버] SetBuffer를 RecvBuffer, SendBuffer로 따로 빼내기 #1
·
공부/게임 서버
패킷 단위로 데이터를 주고 받기 위해서 해야 할 첫 관문은 server 내에 있는 recvBuff를 따로 빼서 관리하는 것이다. 기존 프로그램에서는 SetBuffer를 통해 버퍼 크기, offset을 미리 설정해준 다음에 어떤 변화도 없이 쭉 그대로 사용해왔다. 이렇게 사용하게 되면 문제가 발생한다. TCP 특성상 클라이언트가 보낸 내용이 한 번에 다 오지 않을 수 있다. 앞서 보낸 데이터 중 일부가 버퍼에 데이터가 남아있을 경우 남은 데이터와 새로 보낼 데이터를 함께 보내는데 이때 매우 곤란한 상황이 펼쳐진다. 변화값인 offset을 0으로 설정했기 때문에 남은 데이터를 무시하고 그 위에 새로운 데이터를 덮어쓰게 되는 것이다. 문제를 방지하기 위해서 앞으로는 SetBuffer를 사용하지 않고 RecvB..
[게임 서버] Listener, 네트워크 연결을 기다려보자
·
공부/게임 서버
서버와 클라이언트의 연결을 기다리는 용도의 Listener 클래스는 시작점인 Init, 기다리는 연결이 바로 실행될 수 있음을 확인하는 RegisterAccept, 연결 완료를 담당하는 OnAcceptCompleted, 연결을 받아들이는 Accept 함수로 구성된다. Socket _listenSocket; Action _onAcceptHandler; // Accept가 완료됐을 때 어떻게 처리할 것인지 담당. public void Init(IPEndPoint endPoint, Action onAcceptHandler) { _listenSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); // AddressFami..
[게임 서버] Listener의 반대 개념, Connector에 대해서
·
공부/게임 서버
서버를 만들 때 Listener라는 이름으로 클라이언트의 연결 요청을 기다리는 클래스를 만들게 된다. 그 반대 입장으로 서버에서 서버와 클라이언트의 연결을 직접 하는 클래스를 만들어야 하는데 내가 배운 강의에서는 그 이름을 Connector라 한다. Connector를 따로 만드는 가장 큰 이유 2가지는 1️⃣ 서버 코어 안에서 클라이언트와 연결하는 일이 필요할 때 범용적으로 사용하기 위해, 2️⃣ 나중에 게임 서버를 본격적으로 만들 때 몬스터 관리, 아이템 관리 등 여러가지 서버가 생기게 되는데 이때 그 서버를 서로 연결하고자 할 때 사용하기 위해서다. Connector는 전체적으로 Listener와 흡사한 구조를 갖고 있다. Connector를 호출할 때 사용하게 되는 Connect 함수, 연결을 예..
[게임 서버] 소켓 프로그래밍 BufferList를 사용하여 한 번에 Send
·
공부/게임 서버
기존에 만든 서버에서 사용하던 send는 하나의 내용을 한 번 보내고 다음 내용이 올 때까지 대기하고, 다시 하나의 내용을 받으면 그 하나를 보내는 방식이었다. 코드로 보자면 void RegisterSend() { _pending = true; // send가 될 때까지는 sendQueue에 넣고 실제로 send가 완료됐으면 이어서 queue 확인하고 같은 작업. byte[] buff = _sendQueue.Dequeue(); // 빈 buffer가 아니고 우리가 보내는 크기에 맞는 buffer 설정 // SocketAsyncEventArgs _sendArgs = new SocketAsyncEventArgs(); _sendArgs.SetBuffer(buff, 0, buff.Length); // send를..
[C#] 델리게이트 체인(delegate chain) 단순한 예제
·
언어/C#
델리게이트 객체 내에 여러 메서드에 대한 리스트 정보를 가지게 하는 방법을 델리게이트 체인이라고 한다. static void Main(string[] args) { MyDel myDel = new MyDel(test1); myDel = new MyDel(test2); myDel = new MyDel(test3); myDel(); } 보통 우리가 myDel에 test를 담고 싶으면 =을 사용한다. 위에 내용을 실행하면 이렇게 마지막에 담은 test3의 "세 번째"라는 내용만 출력된다. 만약 내가 test1과 test2에 담긴 내용도 다 보고 싶다면 =을 +=로 변경해주기만 하면 된다. static void Main(string[] args) { MyDel myDel = new MyDel(test1); my..
[게임 서버] 아주아주 간단하게 만드는 소켓 프로그래밍 환경
·
공부/게임 서버
서버와 클라이언트가 통신하기 위해서 서로 연결된 가상의 도로를 만드는데 이 도로의 양 끝을 소켓이라 부른다. 소켓 프로그래밍이란 네트워크를 통해 두 시스템이 소통하는 것을 말한다. 서버 using System; using System.Net; using System.Net.Sockets; using System.Text; namespace Server { class Program { static void Main(string[] args) { // 내 컴퓨터 IP 주소의 문자 이름을 받아오는 함수다. string host = Dns.GetHostName(); // GetHostEntry를 통해 뽑아온 host의 IP 정보, Alias 정보 등을 IPHostEntry에 담는다. IPHostEntry ipH..
[C#] 인터페이스(Interface)란?
·
언어/C#
추상클래스를 이용하다 보면 2개 이상의 클래스를 상속받고 싶을 때가 있다. class Program { public abstract class Sky { public abstract void Fly(); } public abstract class Water { public abstract void Swim(); } public class Monster : Sky, Water // 에러 { public override void Fly() { Console.WriteLine("날기"); } public override void Swim() // 에러 { Console.WriteLine("수영중"); } } 하늘에서는 날고 물에서는 수영하는 몬스터를 만들고 싶지만, 추상 클래스로는 2개 이상의 클래스를 상속받..
[C#] Span이란?
·
언어/C#
ArraySegment와 비슷하게 Span도 배열의 일부를 가져오는 구조체다. ArraySegment보다 활용성이 더 높다. static void Main(string[] args) { int[] arr = { 1, 2, 3, 4, 5 }; int start = 0; int end = 3; Span span = new Span(arr, start, end); Console.WriteLine(span[2]); } 3이 성공적으로 출력된다. ArraySegment와 비슷하게 시작점과 길이를 정해줄 수 있다. 읽기 전용 메서드인 ReadOnlySpan도 있다. 수정 불가하니 더 안전하다. Span의 하위 집단을 가리키는 데에 Span.Slice를 활용할 수도 있다.
[C#] ArraySegment를 이용하여 배열 가져오기
·
언어/C#
배열 안에 일부를 가져오기 위해서 새로운 배열을 파는 것 말고도 ArraySegment를 사용하는 방법이 있다. static void Main(string[] args) { int[] arr = { 1, 2, 3, 4, 5 }; int start = 0; int end = 3; ArraySegment segment = new ArraySegment(arr, start, end); Console.WriteLine(String.Join(", ", segment)); // 배열을 이어붙일 수 있는 간단한 메서드. } ArraySegment의 start는 Offset을 의미한다. 그대로 받아들이면 배열의 변화량을 의미하지만 쉽게 이해하기 위해서는 숫자를 가져올 배열의 시작점을 몇 번째로 할 거냐는 의미다. en..
[Coding] 직렬화(Serialization), 역직렬화(Deserialization)란?
·
공부
직렬화(Serialization) 메모리 상에 인스턴스(객체)로 존재하는 파일을 전송 가능한 형태인 바이트 배열로 만드는 것을 말한다. 역직렬화(Deserialization) 바이트 배열로 만들어진 파일을 다시 인스턴스(객체)로 변화시키는 것을 말한다. 이때 사용하는 것이 바로 BitConverter다. https://codingjin0424.tistory.com/81 [C#] 바이트 배열을 int로, int를 바이트 배열로 using System; using System.Threading; namespace Study { class Program { static void Main(string[] args) { byte[] bytes = { 0, 0, 0, 25 }; if (BitConverter.IsL..
[C#] 바이트 배열을 int로, int를 바이트 배열로
·
언어/C#
using System; using System.Threading; namespace Study { class Program { static void Main(string[] args) { byte[] bytes = { 0, 0, 0, 25 }; if (BitConverter.IsLittleEndian) // 오른쪽 끝에 중요한 게 있다 Array.Reverse(bytes); // 배열을 반대로 정렬 (중요한 걸 왼쪽 끝으로 이동) int i = BitConverter.ToInt32(bytes, 0); Console.WriteLine($"byte -> int : {i}"); byte[] bytes2 = BitConverter.GetBytes(2687511146); Console.WriteLine("int..
[게임 서버] 파싱(Parsing)이란?
·
공부/게임 서버
파싱(Parsing)이란 문서 등의 자료에서 원하는 데이터를 뽑아온 뒤 원하는 모양으로 가공하고 필요할 때 불러오는 것을 말한다. 파싱을 담당하는 프로그램은 파서(Parser)라고 한다.
[게임 서버] DNS란?
·
공부/게임 서버
DNS는 Domain Name System의 약자다. 인터넷 주소창에 우리가 쓰는 Host Domain Name(google.com 등)을 입력했을 때 이를 컴퓨터 네트워크 장치들을 위한 번호인 IP주소로 변환해주는 시스템.
[게임 서버] TCP와 UDP
·
공부/게임 서버
TCP와 UDP는 데이터를 전송할 때 사용하는 프로토콜이다. OSI 7계층과 TCP/IP 모델의 전송계층에서 사용된다. TCP 연결형 서비스다. 전화 통화를 상상해보자. 내가 누군가와 통화를 하고 "안녕하세요? 오늘 날씨가 좋아요"라고 말한다면 듣는 사람의 입장에서도 "안녕하세요? 오늘 날씨가 좋아요"라고 같은 순서로 이야기를 전달받게 된다. TCP도 같다. 논리적 경로가 있으며, 전달 순서가 보장된다. 전달할 데이터를 분실했을 경우 자신이 책임지고 다시 데이터를 보내준다. 신뢰도가 높다. 데이터 흐름 제어, 혼잡 제어를 해준다. UDP 비연결형 서비스다. 오토바이 퀵 배달을 상상하면 쉽다. 퀵은 빠르다. 꼭 전달자가 보내는 순서대로 도착한다는 보장은 없다. UDP도 비슷하다. 연결 없이 통신이 가능하다..