241025 TIL - 주특기 플러스 6

LIHA·2024년 10월 25일
0

내일배움캠프

목록 보기
95/105
post-thumbnail

하드웨어 트러블 - DP 케이블의 모니터 신호 없음 문제

상황: 오늘 새벽까지 잘 켜지던 메인 모니터(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의 작동 원리가 이것이기 때문.

  • NDC 2016에서 듀랑고의 분산 서버 관련 내용에도 이게 있었다. 이거 잘못 처리하면 귀신 쫓아오는 것 처럼 잔상이 남는다.

듀랑고에서의 시야

나의 움직임을 서버에서 처리해주면... 으아아아

대단원의 막!

디렉토리 구조, 클래스, 핑, 레이턴시, 세션, 프로토버프 등등

추가 개발을 해본다면?

게임 종료 조건, 로직
유저 연결 해제 시 게임 세션, 인터벌 매니저에서 세션 삭제
y축 이동 로직
속도 반영

분산서버 구성

보통은 이렇게 떠 있다고 한다. 저 게임 서버, 존 서버 등등도 한두개가 아니라고.

우리 프로젝트는 그야말로 이것 저것 다 합쳐져 있다.
그러나 조금만 프로젝트 규모가 있어도 세션 서버, 매칭 서버, 로케이션 서버, 마스터 서버 (I/O) 등 모두 나눠져 있다.
우리 프로젝트만 봐도 추가되어야 할 부분이 많지만, 벌써 머리가 아프다...

  • 교훈: 웬만하면 나눠서 개발하자

아무튼, 분산 서버에 대해 공부해보자. 공부할 게 아마 많을 것이다.


1주차 복습

client.js도 사실은 그냥 TCP 서버를 하나 더 띄워 소켓으로 통신하겠다는 것

그렇기 때문에 const client = new net.Socket() 으로 소켓 통신을 할 준비를 빡 하는 것.
아래에서 메시지 받는 것도 다 client.on() 으로 이벤트를 듣고 있다.


여러 socket 이벤트들 정리

socket.on('data', (chunk) => {
  console.log('Received data:', chunk.toString());
});

data 이벤트는 서버가 클라이언트로부터 데이터를 받을때마다 발생한다

데이터는 버퍼 형태로 제공되므로 문자열로 바꾸든 지지고 볶고 썰든 내가 원하는 형식으로 처리할 수 있다. data 이벤트는 주로 요청을 처리하거나 응답을 준비할 때 사용한다고.

socket.on('end', () => {
  console.log('Connection ended');
});
socket.on('close', () => {
  console.log('Socket closed');
});

end는 일방의 연결이 끊겼을 때, close는 양쪽의 연결이 완전 끝났을 때

그래서 서버는 'end'로 종료하고 클라이언트가 'close'로 완전히 연결을 끝낸다.
서버가 먼저 연결을 끊으면 마지막으로 클라이언트에서도 문을 닫아주면서 끝나는 것이다.

그럼 end랑 close의 특징이나 다른 쓰임새 같은 게 있는지?🤔

  • end는 '클라이언트가 더 이상 데이터를 보내지 않을 때' 발생하는 이벤트.
    -> 이 이벤트를 통해 연결의 정상종료 여부를 확인할 수 있다. 주로 자원을 정리하거나 로그를 남길 때 사용.

  • close는 '소켓이 완전히 종료되었음을 나타내는' 이벤트.
    end와 달리 양쪽 모두 닫혔음을 의미한다. 리소스 해제나 후속 작업 처리 시 유용하다고.
    헷갈리면 이렇게 생각. 영업을 마감하는거랑 가게 문을 닫고 집에 가는건 다른 시점이고, 가게 문을 닫는게 진짜 끝.

socket.on('error', (err) => {
  console.error('Socket error:', err);
});

error는 close와 짝 - error가 호출되고 나면 바로 연결이 끊긴다

소켓 작업 중 에러가 발생할 경우 처리용으로 호출되는 이벤트. 예외 상황을 처리하고 적절한 로그를 남기거나 에러 대응 할때 꼭 필요하다.


버퍼와 바이트배열

241017 TIL 에서도 공부했지만 기억이 안 나니 다시 정리.
241021 TIL 에 직렬화, 역직렬화와 스택, 힙에 대한 얘기가 나온다.

버퍼를 알려면 바이트배열부터 알아야 해 - 8비트 단위의 데이터 배열

0과 1을 비트라고 했다. 이런 비트가 8개씩 (8비트가 1바이트니까) 묶음으로 있어서.
00000000 -> 0 이고, 111111111 -> 255 라서 0 ~ 255 사이의 값을 가진다. 이걸 16진수로 표현한다

아니, 왜또 16진수로 표현해요? 😫

바이너리 데이터는 원래 보통 16진수로 표현한다. 받아들이자.

그럼 바이트 배열로 쓰는 이유가 뭐에요? 🤔

바이너리 데이터(이진 데이터. 010101...) 로 전송해주려고.
왜 이진 데이터로 전송하냐면, 메모리를 효과적으로 쓸 수 있고 큰 용량의 데이터들을 더 수월하게 보낼 수 있어서.

그래서 버퍼는 대체 또 뭔가요? 바이트 배열이랑 둘이 무슨 사이야? 😵

Buffer 객체는 Node.js에서 바이너리 데이터를 다루기 위한 특별한 객체.
JS의 문자열은 UTF-16 형식으로 인코딩 되어 바이너리 데이터를 효율적으로 처리하기 어렵다.
(∵UTF-16은 16비트(2바이트) 단위로 인코딩. 8비트(1바이트)가 아니라서 힘듬)

  • Buffer 객체는 원시적인 바이너리 데이터를 저장, 조작하는데 최적화 되어 있기 때문에 쓴다!

즉, JS 안에서는 버퍼 객체 == 바이트 배열, 바이트 배열 == 버퍼 객체 라고 생각해도 된다.

버퍼 객체의 장점

  1. 고정된 길이 (8비트, 1바이트니까)
  2. 그로 인한 빠른 접근 (바이트배열 특화인데 바이트배열 전담이니 물만난 고기)

어렵지 않지. 직접 써보자! buffer와 buffer[0]

......? 😵😵😵😵 아냐 어려운 것 같아...
buffer[0] 이면 48 아니야? 왜 72가 나오지?
16진수 48을 10진수로 바꾸면 72이기 때문. (16*4 + 1*8 = 72). 이 72는 아스키코드 숫자다.

이런 현상이 보이는 근본적인 이유는 버퍼에 문자열을 넣을 때 바로 바이트 배열로 넣는게 아니기 때문이라고. 튜터님께서 설명해주신 원리는 다음과 같다.

  1. 일단 문자열을 10진수로 한번 바꿔준다 -> ASCII 코드로 변환하여 각각의 숫자를 취한다.
  2. 바이트 배열은 16진수로 넣기로 약속했으니 위에서 구한 ASCII 숫자를 16진수로 바꿔준다.

서버는 켜지는데 왜 데이터가 안오지? -> 코드를 잘못 써서 socket으로 통신을 안 하고 있었다

원래 이 구조가 맞는건데,

콜백에서 socket을 인자로 받는 const server = ~ 안쪽에다 써줬어야 하는데, 바깥에다 써놓고 데이터가 안 온다고 어리둥절 하고 있었다. (사실상 소켓을 쓰지 않겠다 선언)
이래놓고 socket.on 했을 때 CANNOT_FIND_MODULE 에러가 터지니까 멋대로 server.on으로 바꿔버렸던 건 덤.

메시지, 버퍼, 그리고 소켓을 통한 전달의 기본 구조

내가 보내고 싶은 컨텐츠: const message ~
이걸 감싸줄 버퍼: const buffer = Buffer.from(message)
이 버퍼를 보내줄 소켓 명령어: client.write(buffer)

대강 이런 식으로 보내준다.

profile
갑자기 왜 춤춰?

0개의 댓글