상황: 오늘 새벽까지 잘 켜지던 메인 모니터(DP 연결)가 자고 일어나니 안켜진다. 재부팅을 해도 DP 신호 없음으로 잡혔다. (듀얼 모니터)
HDMI 빼고 DP케이블만 꽂아 재부팅 시도를 하니 메인보드에서 비프음까지 났다.
(길게 1번 짧게 3번 - VGA 문제일 때 이렇게 나온다고 하는데, 모니터를 인식하지 못해도 이런다고.)
이것 때문에 코드카타 시간을 모니터 고치는데 다 써버렸다... 하지만 다행히 해결!
원인: DP를 쓰던 메인 모니터의 DP단자 인식 불량이거나 헐거워서 그랬던 것으로 추정. (본체는 최근 새로 구매, 빡빡하게 잘 꽂히는 양호한 상태)
해결: HDMI를 쓰던 서브 모니터에다 DP를 꽂았더니 해결. 서브 모니터는 DP 단자가 빡빡하게 잘 끼워지는 상태였다
시도한 방법은 다음과 같다.
1. 모니터 - 본체 연결해제, 본체 - 파워선 연결 해제, 파워서플라이 스위치 OFF 후 5 ~ 10분 방전대기 (인터넷에서 본 방법)
2. 본체 - 파워선 연결, 파워서플라이 스위치 ON, 모니터 - 본체 DP 재연결
3. 위 방법 해결 안돼서 재부팅 2번
4. 재부팅해도 해결 안돼서 본체 DP를 서브 모니터에 연결 -> 서브 모니터 정상 출력!
5. 안나오던 메인 모니터는 HDMI - DVI로 연결 -> 메인 모니터도 정상 출력 (DVI 단자가 있는 모니터)
서버가 일정 시간마다 밑도끝도 없이 계속 패킷을 보내는 것과, 유저가 이동을 하거나 할 때 서버한테 위치를 알리면 서버가 응답으로 패킷을 보내주는 두 가지가 있다.
-> 우리 강의에서는 일단 서버가 밑도끝도 없이 계속 패킷을 보내주는 방식으로 쓸 것이다.
그래서 만약 한 유저에게 동기화 요청이 오면, 현재 월드에 있는 유저의 위치를 계산해서 모든 유저의 위치 정보를 응답으로 돌려줘야 한다.
왜 모든 유저의 위치 정보를 응답으로 돌려줘야 하느냐? -> MO나 MMO의 작동 원리가 이것이기 때문.
듀랑고에서의 시야
나의 움직임을 서버에서 처리해주면... 으아아아
디렉토리 구조, 클래스, 핑, 레이턴시, 세션, 프로토버프 등등
게임 종료 조건, 로직
유저 연결 해제 시 게임 세션, 인터벌 매니저에서 세션 삭제
y축 이동 로직
속도 반영
보통은 이렇게 떠 있다고 한다. 저 게임 서버, 존 서버 등등도 한두개가 아니라고.
우리 프로젝트는 그야말로 이것 저것 다 합쳐져 있다.
그러나 조금만 프로젝트 규모가 있어도 세션 서버, 매칭 서버, 로케이션 서버, 마스터 서버 (I/O) 등 모두 나눠져 있다.
우리 프로젝트만 봐도 추가되어야 할 부분이 많지만, 벌써 머리가 아프다...
아무튼, 분산 서버에 대해 공부해보자. 공부할 게 아마 많을 것이다.
그렇기 때문에 const client = new net.Socket()
으로 소켓 통신을 할 준비를 빡 하는 것.
아래에서 메시지 받는 것도 다 client.on()
으로 이벤트를 듣고 있다.
socket.on('data', (chunk) => {
console.log('Received data:', chunk.toString());
});
데이터는 버퍼 형태로 제공되므로 문자열로 바꾸든 지지고 볶고 썰든 내가 원하는 형식으로 처리할 수 있다. data 이벤트는 주로 요청을 처리하거나 응답을 준비할 때 사용한다고.
socket.on('end', () => {
console.log('Connection ended');
});
socket.on('close', () => {
console.log('Socket closed');
});
그래서 서버는 'end'로 종료하고 클라이언트가 'close'로 완전히 연결을 끝낸다.
서버가 먼저 연결을 끊으면 마지막으로 클라이언트에서도 문을 닫아주면서 끝나는 것이다.
end는 '클라이언트가 더 이상 데이터를 보내지 않을 때' 발생하는 이벤트.
-> 이 이벤트를 통해 연결의 정상종료 여부를 확인할 수 있다. 주로 자원을 정리하거나 로그를 남길 때 사용.
close는 '소켓이 완전히 종료되었음을 나타내는' 이벤트.
end와 달리 양쪽 모두 닫혔음을 의미한다. 리소스 해제나 후속 작업 처리 시 유용하다고.
헷갈리면 이렇게 생각. 영업을 마감하는거랑 가게 문을 닫고 집에 가는건 다른 시점이고, 가게 문을 닫는게 진짜 끝.
socket.on('error', (err) => {
console.error('Socket error:', err);
});
소켓 작업 중 에러가 발생할 경우 처리용으로 호출되는 이벤트. 예외 상황을 처리하고 적절한 로그를 남기거나 에러 대응 할때 꼭 필요하다.
241017 TIL 에서도 공부했지만 기억이 안 나니 다시 정리.
241021 TIL 에 직렬화, 역직렬화와 스택, 힙에 대한 얘기가 나온다.
0과 1을 비트라고 했다. 이런 비트가 8개씩 (8비트가 1바이트니까) 묶음으로 있어서.
00000000 -> 0 이고, 111111111 -> 255 라서 0 ~ 255 사이의 값을 가진다. 이걸 16진수로 표현한다
바이너리 데이터는 원래 보통 16진수로 표현한다. 받아들이자.
바이너리 데이터(이진 데이터. 010101...) 로 전송해주려고.
왜 이진 데이터로 전송하냐면, 메모리를 효과적으로 쓸 수 있고 큰 용량의 데이터들을 더 수월하게 보낼 수 있어서.
Buffer 객체는 Node.js에서 바이너리 데이터를 다루기 위한 특별한 객체.
JS의 문자열은 UTF-16 형식으로 인코딩 되어 바이너리 데이터를 효율적으로 처리하기 어렵다.
(∵UTF-16은 16비트(2바이트) 단위로 인코딩. 8비트(1바이트)가 아니라서 힘듬)
- Buffer 객체는 원시적인 바이너리 데이터를 저장, 조작하는데 최적화 되어 있기 때문에 쓴다!
즉, JS 안에서는 버퍼 객체 == 바이트 배열, 바이트 배열 == 버퍼 객체 라고 생각해도 된다.
- 고정된 길이 (8비트, 1바이트니까)
- 그로 인한 빠른 접근 (바이트배열 특화인데 바이트배열 전담이니 물만난 고기)
......? 😵😵😵😵 아냐 어려운 것 같아...
buffer[0]
이면 48 아니야? 왜 72가 나오지?
16진수 48을 10진수로 바꾸면 72이기 때문. (16*4 + 1*8 = 72)
. 이 72는 아스키코드 숫자다.
이런 현상이 보이는 근본적인 이유는 버퍼에 문자열을 넣을 때 바로 바이트 배열로 넣는게 아니기 때문이라고. 튜터님께서 설명해주신 원리는 다음과 같다.
- 일단 문자열을 10진수로 한번 바꿔준다 -> ASCII 코드로 변환하여 각각의 숫자를 취한다.
- 바이트 배열은 16진수로 넣기로 약속했으니 위에서 구한 ASCII 숫자를 16진수로 바꿔준다.
원래 이 구조가 맞는건데,
콜백에서 socket을 인자로 받는 const server = ~
안쪽에다 써줬어야 하는데, 바깥에다 써놓고 데이터가 안 온다고 어리둥절 하고 있었다. (사실상 소켓을 쓰지 않겠다 선언)
이래놓고 socket.on 했을 때 CANNOT_FIND_MODULE 에러가 터지니까 멋대로 server.on으로 바꿔버렸던 건 덤.
내가 보내고 싶은 컨텐츠: const message ~
이걸 감싸줄 버퍼: const buffer = Buffer.from(message)
이 버퍼를 보내줄 소켓 명령어: client.write(buffer)
대강 이런 식으로 보내준다.