목록프로그래밍/C# 게임서버 (25)
有希
1. new Socket, Listen, Bind를 따로 Listen 클래스의 Init()함수 생성 후, 안으로 이동 시킨다. 이후 Accept함수를 두어 전 역변수 _listenSocket을 만 든 뒤, 이것에서 .Accept() 하여 반환한다. 한 가지 생각해 봐야 할 것이 Accept() 함수는 blocking계열의 함수이므로, 클라이언트로부터 연결이 들어올 때까지 다음 라인으로 넘어가지 않고 기다린다.(Accept, Receive, Send는 모두 blocking 계열) 이러한 blocking계열의 함수들은 효율을 위해 비동기 방식으로 처리해야 한다. Accept->AccepSync로 바꾸어 준다. 2. 이를 위해서 2가지 함수를 클래스 내에 만들어준다. ClientAccept()와 AcceptC..
클라 1. 소켓 준비 2. 서버 주소로 connect 3. 1번 소켓으로 통신 서버 1. Listener 소켓 준비 2. Bind(서버주소/port를 listener소켓과 연동) 3. Listen 4. Accept 5. Accept에서 얻은 소켓으로 통신 소켓 프로그래밍을 네트워크 프로그래밍 수업 때 썼던거 같은데, Listener 소켓의 존재와 Accept에서 받은 통신용 소켓의 존재가 굉장히 헷갈렸다. 아니 왜, 바로 Accept소켓으로 받아서 그거로 통신하지 않느냐고... 지금이야 그냥 받아들여졌는데, 이렇게 생각하면 편하다. Listen 소켓을 하나 두어 들어오는 모든 요청을 이것으로 처리한다. 요청을 처리해서 이상이 없으면 Client - Server 통신용 소켓을 하나 만들어 준다. 뭔가 검문..
학교 다닐땐 OSI를 외웠던거 같은데...억지로 A(pplication) , P(hysical) 등 앞글자만 따서 요상한 글자 외우느라 고생했는데, 강의에서 뭔가 외우기 쉽고 이해가 잘 되게 설명해주셔서 잘 외워졌다 -_-.. TCP/IP 모델(5단계) OSI와 비교 - 7계층, 주소: 도메인 어플리케이션(유저 인터페이스 HTTP, FTP, DNS) – 상품을 준비하는 단계 트랜스포트(전송확인/오류 해결 TCP, UDP) – 배송 정책 OSI와 비교 - 3계층 주소: IP, 라우터 네트워크(네트워크 간 경로 설정 IPv4, IPv6, 관련 장치: 라우터) – 아파트 단지 간 송신 OSI와 비교 - 2계층 주소 : MAC, 스위치 데이터 링크(네트워크 내 경로 설정 이더넷, PPP 관련장치: 스위치) – ..
서버 프로그래밍은 안정성이 굉장히 중요한 이슈이다. 많은 동시 접속자를 버티면서도 해킹 위험도 막아야 한다. 이런 상황에서 네트워크 지식이 없으면 어떻게 해결해야 하는지 아예 감도 못잡을 수 있다. 네트워크 패킷을 보내는 방식은 택배와 굉장히 비슷하다. 택배를 무조건 출발지->도착지로 다이렉트하게 보내는 것이 아닌 CJ대한통운 처럼 경유지(옥뮤다)를 하나 정해서 모든 택배는 출발지->경유지->도착지로 보낸다. (이런 방식을 Hub - and - Spoke 방식이라 부르던거 같던데) 이 방식을 사용한다면, 서로 다른 100개의 출발지, 100개의 도착지가 있을때, 이들을 서로 가장 빠르게 연결하는 각각의 경로 100*100=10000개를 외우고 이용할 필요가 없이, 출발지 - 경유지, 경유지 - 도착지 경..
전역변수인데, Thread마다 고유하게 접근할 수 있는(각자 따로 가지는 전역변수) 전역변수 멀티스레드 환경이라고 해서 무조건 JobQueue에서 Lock걸고 빼와서 작업하고 하면 효율이 굉장히 나쁘다. 와우에서 게임에서 하나의 게임로직으로 사람들이 몰릴 때(쟁이나...공대라던가..) 하나씩 락을 걸어서 처리하게 되면 사람이 엄청나게 모였는데, 굉장한 렉을 느끼게 된다. Heap와 데이터 영역(static)은 모든 Thread가 공유하고, Stack은 각자 따로 가진다. Stack은 함수 호출같은 주소가 채워졌다가 사라졌다가 하는 불안정한 영역이므로 여기에 데이터를 저장한다는건 좀 그렇다. 그래서 따로 ThreadLocalStorage라고 부르는 Thread별로 별도의 메모리 공간을 잡아준다. 자기가 사..
메이플 데일리기프트를 생각해보면, 데일리기프트 품목은 거의 항상 같다. 이번처럼 뭔가 대란이 일어나서 품목이 바뀌지 않는 한은 몇 년에 한 번? 정도 바뀐다. 물론, GM이 툴로 품목을 바꾸는 것은 혹은 자동화 시스템으로 품목을 바꾸는 것은 패치 중에 할 것 같지만?? 만약에 실시간으로 바꾼다고 하면, 유저들이 품목을 바꾸는 동안에는 읽으면 안되고, 잠깐 12시 넘어가는, 월이 넘어가는 동안 로딩중입니다 화면이 뜨고 품목 변경이 완료되면 떠야 하기 때문에 Lock을 사용해야 한다. 그런데, 이를 위해서 항상 Lock을 잡고 수 천, 수 만의 유저들이 한 명씩만 품목 리스트를 읽으면 막대한 손해이다. 모든 유저가 Read만 하는 것은 멀티 스레드에서도 아무런 문제가 되지 않으므로 ReadLock, Writ..
코드는 강좌를 구매해주시길 바란다. 구현 방법만 기록. Lock은 3가지로 나눌 수 있다. 1. SpinLock 2. RandomLock?(Context Switching) 3. AutoResetEvent SpinLock 잠금이 풀릴 때까지 계속 루프를 돌며 대기한다. 이를 구현하기 위해 bool _locked를 두고, _locked가 true이면 while로 기다리다가 while을 빠져나오면 _locked를 다시 true로 바꾸는 것을 생각해 볼 수 있는데, 이상적으로 작동하지 않는다. 왜냐하면 while에서 _locked를 체크하고, _locked를 바꾸는 부분까지 Atomic하게 이루어져야 한다. 그렇지 않으면 내가 true로 바꾸려는 순간 다른애도 "어? lock 열렸네?" 하고 들어와서 나랑 동..
일반적인 상황에서 데드락이 발생하는 경우는 복잡한 상황인 경우가 많다. 자물쇠1,2를 동시에 2명이 잡았다고 가정하자. 근데, 자물쇠 1,2를 한 명이 모두 획득해야 방에 들어갈 수 있다고 가정하면 자물쇠를 잡은 2명은 각자의 자물쇠를 꽉 쥐고, 서로의 자물쇠를 노리고 있다. 이런 경우에는 서로의 락을 영원히 기다리게 된다. 이를 해결하기 위해, 규약을 하나 정해서 무조건 낮은 숫자의 자물쇠를 먼저 획득하게 한다면 1을 먼저 잡은 쪽은 2도 획득할 수 있다. 1을 잡지 못한 쪽은 2가 아직 획득 가능하지만 규약이 있으므로 1을 기다린다. 혹은, 시간제한을 걸어두고 일정시간이 지나면 자신의 락을 해제하고 다시 락을 얻도록 하는 것도 있으나 예시에서는 첫번째 방법이 더 안정적이라고 생각된다. 왜냐하면, 둘 ..
멀티스레드 환경에서 어떤 메모리를 읽는 것은 전혀 문제가 되지 않는다. 즉, 값을 바꾸는 작업이 아니면 문제가 되지 않는다. 하지만, 모두가 읽다가 한 녀석이 쓰기 작업을 하게 되면 읽는 작업도 문제가 되버린다. 여러 Thread가 동시다발적으로 접근하면 문제가 되는 부분을 임계구역(Critical Section)이라 한다. 가장 기초적인 Lock 방법으로는 다음과 같은 방법이 있다. static object _lock = new object(); for() { Monitor.Enter(_obj); number++; Monitor.Exit(_obj); } 이렇게 하면 두 스레드에서 동시에 ++ -- 연산을 한다고 해도 의도한 대로 0이 나온다. 즉, 내가 Enter하는 순간 다른 녀석은 Enter하지 못..
for(int i=0; i