봄링크 게임2-서버 생성
다시 시작
원래 구직준비를 하며 틈틈이 만들던 프로젝트였으나…
반년 넘게 지나서야 이 프로젝트를 다시 만지게 되었다.
지금은 개발직종이 아니다 보니 개발실력을 잃어서는 안되고 하니..
아무튼 올해 내로 구현하는 것까지 목표로 삼고,
지난번 게임의 백엔드 논리를 구현했으니 이번에는 그걸 실제 서버로 구연해보겠다.
3티어 구조
웹 앱을 만들 때는 크게 2(투)-티어 또는 3(쓰리)-티어 구조로 개발하기 마련이다.
2 티어는 클라이언트&서버↔DB 로 이루어진 구조이다.
클라이언트가 정보를 표현하는 것과 동시에 기능(백엔드 논리)까지 구현한다.
이렇게 이루어진다는 것이다. 즉 흔히 말하는 클라이언트와 서버가 합쳐졌다고 보면 된다.
반면 3 티어는 클라이언트↔서버↔DB 로, 백엔드 논리만을 담당하는 서버를 따로 둔다.
클라이언트는 단순 서버에서 처리된 데이타를 표시하기만 할 뿐이다.
위 로그인 기능을 보면
이렇게 단순히 사용자 정보만을 입력하고 표시하는 클라이언트(웹)과 사용자 정보를 읽어들여 로그인 여부를 처리하는 서버(WAS), 사용자 정보가 들어있는 DB 이렇게 3개로 나뉘어졌다!
이러한 구조는 2-티어보다 서버 한대가 더 늘어나 추가 처리를 해줘야 하는 단점이 있지만,
웹사이트의 보안성을 높이고(1.로그인 정보 전송에서 암호화를 하는 등)
확장이 용이하기에(서버는 데이타만 받으니 그걸로 추가 작업을 하는 등)
디자인 패턴을 적용하는 큰 프로젝트에는 웬만하면 3티어 구조를 채택한다 보면 된다.
본 프로젝트도 3-티어 프로젝트로 시작하고 있다.
- 게임을 표시하는 웹 프론트-Next.js
- 백엔드 알고리듬을 수행하는 WAS서버-Python Django
- 각종 정보를 담는 DB-미구현
이렇게 진행하겠다.
참고로 WAS 서버는 웹 어플리케이션 서버(Web Application Server)의 약자로, 웹페이지의 기능을 구현하는 서버 대충 이런 뜻이다.
흔히 말하는 API 서버도 WAS에 해당된다. 서버 기능을 API를 통해 전달한다는 뜻이니..
서버 만들기
게임이 실질적으로 실행되는 WAS 서버는 파이썬 Django로 생성하고 있다.
간단한데다 무엇보다 ORM 지원으로 DB연결이 쉽다 보니…
Django 프로젝트 생성
Django 프로젝트 생성은 파이썬이 깔려 있다는 전제하에, 다음과 같이 진행한다.
1
2
pip install django
django-admin startproject (프로젝트 이름)
참고로 가상 환경(venv)을 사용하면 각 프로젝트별로 별개의 파이썬 버젼/pip 팩키지들을 관리할 수 있으니 이왕이면 환경 내에서 위 스크립트를 실행해주자.
사용 방법은
1
2
3
4
5
6
7
python -m venv (가상환경 이름-보통 .venv)
# 윈도우
(위에서 생성된 가상환경 폴더)\Scripts\activate.bat
# 리눅스/유닉스
source (가상환경 폴더)/bin/activate
다음과 같다. 이왕이면 보기 깔끔하게 Django 프로젝트 위에 상위 폴더를 만들어 가상환경과 같이 넣어주자.
프로젝트 안에는 여러 앱을 생성할 수 있다. 각 기능별로 앱을 따로 만들면 편리하겠죠~ 여기서는 Game이라는 앱을 생성하겠다.
1
python manage.py startapp Game
Game 폴더가 생길 것이다. 그 안에 예전 만들었었던 알고리듬이 들어있는 base.py 를 넣어주자.
REST API 구현
웹 클라이언트와의 통신은 간편하게 REST API 형식으로 하겠다.
REST API 설명은 예전에 말했으므로 패쓰~
우선은 base.py에서 게임판을 보기 쉽게 변환해주는 returnBoard() 메쏘드를 만들어주자.
board 내용을 읽어다 불은 1, 폭탄은 화살표로 변환해주는 간단한 기능이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def returnBoard(self):
temp = [['_' for i in range(self.karo+2)] for j in range(self.sero+2)]
for i in range(self.sero+2):
for j in range(0,self.karo+2):
if j==1 or j==self.karo+1:
temp[i][j]='|'
if j==0 or j==self.karo+1:
if (j,i)==self.Fire.getFire():
temp[i][j]='1'
else:
temp[i][j]='0'
else:
x,y,s = self.board[i][j].getBomb()
if s==0:
temp[i][j]='↑'
elif s==1:
temp[i][j]='→'
elif s==2:
temp[i][j]='↓'
elif s==3:
temp[i][j]='←'
else:
temp[i][j]='0'
return temp
Game 클래쓰도 다음과 같이 수정해준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Game:
timer=0
def __init__(self,karo,sero):
self.Link = Link(karo,sero)
self.Link.initBoard()
def printGame(self):
# self.Link.printBoard()
return self.Link.returnBoard()
# 게임 진행은 아직 필요없으니 주석처리
'''
while self.Link.playBoard():
time.sleep(1)
os.system('clear')
# self.Link.printBoard()
for i in self.Link.returnBoard():
print(i)
'''
이제 printGame() 메쏘드를 실행하면 최초의 게임판 화면(2차원 배열)을 넘겨주는 것이다.
Django는 기본적으로 웹 서버 프레임웤이지만, REST API를 통해 WAS로도 만들어주는 django-rest-framework라는 pip 라이브러리를 제공하고 있다.
1
pip install djangorestframework
이렇게 pip로 간편 설치 가능하다.
설치 되면 WAS 프로젝트 내 settings.py에 다음과 같이 추가해준다.
1
2
3
4
INSTALLED_APPS = [
...,
'rest_framework'
]
그 다음, 앱 폴더(여기서는 Game) 내의 views.py에서 다음과 같이 만들어준다.
views.py는 실제 기능이 들어가는 중요한 파일이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from django.shortcuts import render
# djangorestframework 기능 가져오기
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
# base.py에서 Game 가져오기
from .base import Game
# 최초 실행시 게임판을 출력해주는 테스트 클래스
class TestAPI(APIView):
# get은 APIView에서 제공하는 메쏘드-get 요청일 때 아래 실행, 당연히 post도 존재
def get(self,request):
# request에서 보드 크기 가져오기-기본값 가로 5, 세로 10
game = Game(int(request.query_params.get('x',5)), int(request.query_params.get('y',10)))
# HTTP 200으로 time: 1(최초), board:게임판(2차원 배열) 출력
return Response(data={
"time" : '1',
"board" : game.printGame()
},status=status.HTTP_200_OK)
물론 여기서 예외 처리 등 더 해줘야겠지만, 일단은 표시하는 것에만 신경쓰므로 넘어가자.
위 TestAPI 클래쓰는 djangorestframework에서 제공하는 APIView를 상속받는, 하나의 API라고 보면 된다.
get/post 메쏘드를 작성하면, 클래쓰에서 오버라이딩 되어
http 통신의 get/post 여부에 따라 아래 논리가 작동되는 것이다.
get 요청은 보통 파라메타를 url에 작성하기 때문에, 이를 가져오기 위해서는
request.query_params.get(‘파라메타 이름’,(기본값)) 을 사용한다.
기본값은 생략 가능하다.
마지막으로 위 API를 url과 연결하기 위해,
프로젝트 폴더의 url.py에서 아래 내용을 입력해준다.
1
2
3
4
5
6
7
8
from django.contrib import admin
from django.urls import path
from Game.views import TestAPI
urlpatterns = [
path('admin/', admin.site.urls),
path('test/', TestAPI.as_view())
]
이는 Game 앱의 views에 있는 TESTAPI를 (최상단 도메인)/test/ 로 받는다는 것이다.
즉 …/test 으로 GET 요청을 보내면, TestAPI 클래쓰의 get 메쏘드가 실행된다!
테스트
로컬환경에서 테스트가 가능하다.
최상위 프로젝트 폴더에서 파워쉘 등을 띄운 다음
1
python manage.py runserver
를 하면 굳이 아파치 등을 깔지 않아도 로컬 테스트가 가능하다.
실행하면 위 화면이 나오는데, http://127.0.0.1:8000/ 프로젝트의 최상단 도메인이다.
참고로 127.0.0.1은 localhost와도 동일하다. OS의 hosts 파일에 그렇게 되어 있기 때문이다.
이제 그러면 포스트맨 등을 통해 http://127.0.0.1:8000/test 또는 http://localhost:8000/test 으로 GET 요청을 보내보자.
가로를 3으로, 세로를 5로 입력하니 board 에 최초 실행시의 화면 값이 나온다.
1
2
3
4
5
6
7
8
9
10
{
"time":"1",
"board":[["1","0","0","0","0"],
["0","0","0","0","0"],
["0","0","0","0","0"],
["0","←","↓","↑","0"],
["0","↓","↓","↑","0"],
["0","↑","↓","→","0"],
["0","↓","↓","←","0"]]
}
위처럼 board 맨 아래 줄은 다음에 올라올 폭탄이고, 맨 위 줄은 여기까지 올라오면 게임오버 된다.
그리고 가로 양옆은 불이 내려가는 곳이고.
파라메타를 입력하지 않으면 아래와 같이 기본값인 가로 5, 세로 10으로 생성되어 나온다!
다음 시간에
다음 시간에는 이를 웹으로 표시하기 위해, FE 생성을 다루겠다.