전희성 교수님의 요청으로 작성된 포스트입니다. 많은 학생들에게 도움이 되었으면 합니다.

Unity를 아이폰용(ios)으로 빌드하는 방법을 알려드리겠습니다.

 

우선 Unity에서 이러한 작업을 수행하기 위해선 다음과 같은 조건이 필요합니다.

테스트 디바이스(아이폰)의 경우 ipone 5 이상이여야 하며, iOS의 버전은 8.0 이상이여야 합니다.

당연한 이야기지만 iphone 개발의 경우 Macbook이 무조건적으로 필요합니다...

mac이 없이 해킨토시로 어떻게든 하시려고 하는 분이 계신데 별로 추천 드리지 않습니다.

그냥 안드로이드 공기계를 구해서 안드로이드로 작업하시는 것이 정신건강에 좋을 것 같네요. (진심입니다)

 

그럼 설명을 진행하겠습니다.

 

Unity의 버전은 수업에서 사용하는 버전인 Unity 2019.1.15f1 을 사용합니다.

다만 안드로이드가 아닌 ios에서 작동되야 하므로 아래와 같이 체크를 해줍니다.

 

다음으로 프로젝트를 생성합니다. 간단하게 프로젝트명을 Cardboard로 지어주었습니다.

 

프로젝트를 열면 아래와 같은 화면이 표시 됩니다.

 

다음으로 GoogleVRForUnity파일을 받아와야 합니다.

github.com/googlevr/gvr-unity-sdk/releases

 

Releases · googlevr/gvr-unity-sdk

Google VR SDK for Unity. Contribute to googlevr/gvr-unity-sdk development by creating an account on GitHub.

github.com

위 링크에 접속하시면 최신 릴리즈 버전(2020년 11월 기준: 1.200.1)이 있습니다.

unitypackage파일을 다운로드 받아주세요.

 

 

다음으로 받은 unitypackage파일을 임포트 해주어야 합니다.

아래와 같이 Assets - Import Package - Custom Package 를 눌러 줍니다.

 

 

아까 다운로드 받아두었던 파일을 선택해 Open 버튼을 클릭합니다.

아래와 같이 패키지 임포트 파일의 체크 리스트가 표시됩니다.

다른 것 건드릴 필요없이 그대로 import 버튼을 눌러줍니다.

 

하단에 프로젝트 내 폴더 뷰창을 보시면 Assets 폴더 내에 GoogleVR 폴더가 성공적으로 임포트 되있는 것을 확인할 수 있습니다.

 

다음으로 Assets -> GoogleVR -> Prefabs 폴더에 들어가 GvrEditorEmulator.prefab 파일을 선택한 뒤,

Scene에 드래그 앤 드롭 방식으로 추가시켜줍니다.

 

 

다음으로 360도 파노라마 뷰가 가능한 이미지 파일을 임포트 해보겠습니다.

강의에서 사용하는 이미지 파일을 그대로 사용해보겠습니다.

해당 이미지는 아래 링크에서 받으실 수 있습니다.

 

pixexid.com/image/8hw0clw-360-panorama-miami

 

360 panorama miami free images

thet Curated by ਲਃਲਃਲਃਲਲਃਲਃਲਃਲਃਲਲਲਃਲਃਲ ਲਃਲਃਲਃਲਲਃਲਃਲਃਲਃਲਲਲਃਲਃਲ

pixexid.com

우측 상단에 Download 버튼을 눌러 다운로드 받아주세요.

 

다음으로 Unity에서 Assets -> Import New Asset을 클릭합니다.

그 다음 받았던 이미지 파일을 임포트시켜 줍니다.

 

 

 

 

이미지 추가 후 아래와 같은 화면이 보여집니다.

아직까지는 딱히 어려운 것은 없네요

 

 

이미지 파일에 inspector에서 Texture Shape를 Cube로 Mapping 을 Latitude-Logitude Layout으로 변경해줍니다.

이후 아래와 같이 로딩이 진행됩니다.

 

 

로딩이 끝나면 평면이었던 이미지 파일이 구형 모양이 됩니다.

 

 

 

다음으로 Assets -> Create -> Material 을 클릭해 추가시켜 줍니다.

 

 

추가한 Material의 이름을 Sky로 변경해 줍니다.

 

해당 Material의 Shader를 Skybox/Cubemap으로 설정해줍니다.

 

또한, Cubemap(HDR)에 있는 select를 눌러 아까 생성해두었던 구 모양의 파라노마 사진을 선택해줍니다.

 

위 작업이 끝났다면 아래와 같이 Sky meterial에 이미지가 적용되었음을 확인 할 수 있습니다.

 

 

위 Sky Meterial을 드래그 앤 드롭 방식으로 Scene 위에 올려줍니다.

 

제대로 작업하셨다면 아래와 같은 화면을 볼 수 있습니다.

 


위의 내용까지는 프로젝트를 만드는 과정이었습니다.

이제부터는 ios 위에 올려야 하는 작업입니다.

 

우선 Unity에서 File -> Build Settings를 클릭합니다.

 

 

다음으로 Platform에서 iOS를 선택한 뒤 Switch Platform을 눌러 플랫폼을 변경해줍니다.

플랫폼이 정상적으로 변경되었다면 Player Settings를 클릭합니다.

이후 Other Settings에서 Bundle Identifier을 변경해줍니다. 저의 경우 com.sidongmen.cardboard로 하였습니다.

Scripting Runtime Version은 .Net 4.x Equivalent 로 설정해줍니다.

 

다음으로 XR Settings 탭에서 Virtual Reality Supported 를 체크해줍니다.

우리는 Cardboard에서 사용할 것이므로 Cardboard를 추가해줍니다.

이 작업을 건너 뛸 경우 xcode에서 빌드 시 에러가 발생하니 주의하세요.

 

다음으로 아까 열었던 Build Settings에서 Build 버튼을 눌러줍니다. 폴더명을 build로 해주고 Save를 눌러줍니다.

 

다음으로 xcode를 열어줍니다.

xcode가 없으시면 설치해주세요. 따로 설치방법은 올리지 않겠습니다..ㅎㅎ

xcode 아이콘

xcode를 실행한 뒤 아까 생성했던 build 폴더에 들어가 .xcworkspace 라는 확장자를 가진 프로젝트 파일을 열어줍니다.

xcodeproj가 아니라 xcworkspace입니다!! 헷갈리면 빌드가 안되니 주의하세요!

정상적으로 프로젝트를 열었다면 아래와 같은 화면을 보실 수 있습니다.

이제 USB와 아이폰을 연결해줍니다.

 

아래와 같은 알림창이 뜨면 신뢰를 눌러줍니다.

제 iphone 이름은 Miley입니다.

xcode에서 디바이스가 인식되었음을 알 수 있습니다.

 

이대로 상단에 있는 플래이 버튼을 눌러 빌드를 진행하면 Signing 오류가 발생합니다.

프로젝트를 눌러 Signing & Capabilities 탭에 들어갑니다.

 

Automatically manage signing을 체크하여 계정을 설정해줍니다.

 

개발자 계정의 경우 매년 129,000원 정도를 지불해야 합니다.

굳이 앱스토어에 올릴 게 아니고 내 디바이스에서 테스트를 할 것이니 가입비를 지불하지 않고

개인 계정을 사용하여 테스트 할 수 있습니다.

 

저는 개발자 계정을 사용하지 않고 개인 계정을 사용하였습니다.

 

개인 계정을 추가하는 방법은 아래링크를 참고해주세요.

www.egovframe.go.kr/wiki/doku.php?id=egovframework:hyb3.5:hrte:runiphone

 

egovframework:hyb3.5:hrte:runiphone [eGovFrame]

아이폰의 경우 iOS7이상에서는 애플 개발자계정없이도 애플계정으로 아이폰에 빌드할수 있도록 변경되었다. iOS 7.0 이상 설치된 아이폰 Xcode에 아이폰의 애플계정이 등록되어야 한다. 보안인증이

www.egovframe.go.kr

 

개인 계정을 아래와 같이 설정해줍니다.

 

이제 다시 플레이 아이콘 버튼을 눌러 빌드를 진행해줍니다.

빌드 시 Could not launch 권한 에러가 발생할 경우

아이폰에서 설정 -> 일반 -> 기기 관리를 눌러 해당 앱의 권한을 허용해줍니다.

 

앱이 잘 설치되었음을 알수 있습니다.

 

 

 

앱을 실행해보았습니다. 잘 작동하네요 ㅎㅎ

 

 

 

 

교수님께서 나누어 주셨던 Cardboard를 사용해보았습니다.

 

잘 작동하는 것을 확인했습니다.

 

네.. 이렇게 xcode를 통해 아이폰용 Unity 를 빌드하는 법을 알아보았습니다.

설명이 미흡한 부분 죄송합니다 ㅠㅠ

쭉 빌드를 해보니 아래에 해당하시는 분이면 안드로이드를 사용하시는게 좋을 듯합니다.

 

1. 맥북이 없다 (<- 이건 대체가 불가능)

2. 아이폰이 너무 구형이다.(저의 경우 iphone6)

3. xcode를 다뤄본 경험이 많지 않음.

 

 

네 뭐 그렇습니다..

긴글 읽어주셔서 감사합니다.

 

 

github.com/sidongmen

 

sidongmen - Overview

Be creative. sidongmen has 4 repositories available. Follow their code on GitHub.

github.com

 

 

 

SQL 기본 명령 1

사용자의 모든 테이블 보기 SELECT * FROM tab;

-scott 사용자 대표 테이블 : DEPT, EMP, SALGRADE, BONUS

 

테이블 구조 보기 DESC 테이블명

 

NULL 데이터

  • 0(zero)도 아니고, 빈 공백도 아니

  • 미확정(해당 사항 없음), 알 수 없는(unknown) 값을 의미

  • 연산, 할당, 비교가 불가능 (연산을 할 경우 결과는 null값)

 

별칭(alias)

-쿼리문의 결과가 출력될 때, 컬럼의 이름이 지정한 컬럼명의 대문자로 출력됨

 (연산 후의 결과 컬럼명이 보기에 좋지는 않음)

 ① 컬럼명 as 별칭

 ② 컬럼명 별칭

 ③ 컬럼명 “별칭” //별칭에 공백이나 특수문자, 대소문자 구별을 사용

 

연산식 별칭 처리 시

SELECT empno “사 번”, ename “사 원 명” , sal*12 “연봉” FROM emp;

 

|| 연결 연산자(concatenate)

  • 기존 컬럼값에 문자열을 추가하여 연결하기 위한 연산자

 

중복되는 컬럼을 한 번씩만 보여주기 위한 DISTINCT 키워드

  • 중복된 값은 제외하고 한 개 값만 출력

SELECT DISTINCT deptno FROM emp;



SQL 기본 명령 2 - (1)

where 조건절 : 조건을 이용하여 특정 레코드를 조회하기 위한 절

  • 실무에서 테이블의 모든 테이터를 검색하는 일은 거의 없음.

  • 많은 데이터 중에서 필요한 데이터만 검색하는 경우가 대부분임.

 

비교연산자

-where 절에는 하나 또는 그 이상의 조건을 설정할 수 있음

-조건에 사용하는 비교연산자

=(같다), >(크다), <(작다), >=크거나 같다, <=작거나 같다, <>(같지않다)

 

특정 데이터 추출 : 숫자 비교

-부서번호가 10번인 사원만 출력 SLECT *FROM emp WHERE deptno = 10;

 

-급여가 2000이상인 사원의 사번, 이름, 급여를 출력

 SELECT empno, ename, sal FROM emp WHERE sal >= 2000;

특정 데이터 추출 : 문자열 비교

-문자열은 단일 따옴표 안에 표시함 : ‘문자열’

 

-FORD 사원의 사번, 이름, 급여 출력

 SELECT empno, ename, sal FROM emp WHERE ename = ‘FORD’;

 SELECT empno, ename, sal FROM emp WHERE ename = ‘Ford’; 

 

፠비교값은 대소문자를 구별한다는 것에 주의!

 

특정 데이터 추출 : 날짜 데이터 비교

-날짜 데이터는 단일 따옴표 안에 표시함 : ‘yyyy/mm/dd’

 

-1982년 1월 1일 이후에 입사한 사원의 이름, 입사일자 출력

SELECT ename, hiredate FROM emp WHERE hiredate >= ‘1982/01/01’;

 

LIKE 연산자

-WHERE ename = ‘홍길동’

 : 정확히 사원이름이 홍길동인 사원만 검색

 

(Q) 성이 홍씨인 사원만 출력

  • WHERE ename = ‘홍’

  : 정확히 사원이름이 홍인 사원을 검색

 

-와일드 문자

% : 0개 이상의 문자열 대체

밑줄문자(_) : 단 1개 문자 대체

 

예시) 사원이름이 J로 시작 : ‘J%’

         사원이름에 A를 포함 : ‘%A%’

         사원이름 두 번째 문제가 A : ‘_A%’

 

-와일드 문자 비교 : LIKE 연산자

컬럼명 LIKE 와일드문자열(pattern)

 

-이름이 J로 시작하는 사원의 사번, 이름 출력

SELECT empno, ename, FROM emp WHERE ename LIKE ‘J%’;

 

-이름에 A를 포함하는 사원의 사번, 이름 출력

SELECT empno, ename FROM emp WHERE ename LIKE ‘%A%’;

 

-이름이 N으로 끝나는 사원의 사번, 이름 출력

SELECT empno, ename FROM emp WHERE ename LIKE ‘%N’;

 

-이름의 두 번째 문자가 A인 사원의 사번, 이름 출력

SELECT empno, ename FROM emp WHERE ename LIKE ‘_A%’;



SQL 기본 명령 2 - (2), (3)

 

 IN 연산자

  • 여러 개의 값 중에서 일치하는 것이 있으면 조건에 맞는 것으로 함

  • 논리연산자 OR 대신 사용 가능, 날짜와 문자열 비교도 가능

 

부서번호가 10, 20인 사원의 사번, 이름, 부서번호 출력

SELECT empno, ename, deptno FROM emp WHERE deptno IN (10, 20);

 

BETWEEN A AND B 연산자

  • A에서 B까지의 특정 범위 값을 조회하는 연산

  • 논리연산자 AND 대신 사용 가능

 

급여가 2000에서 4000 사이인 사원의 사번, 이름, 급여 출력

SELECT empno, ename, sal FROM emp WHERE sal BETWEEN 2000 AND 4000;

 

논리 연산자 : AND, OR, NOT

  • WHERE 절에 조건이 두 개 이상일 경우 : AND, OR

  AND : 두 조건을 모두 만족해야 검색 (조건1 AND 조건2)

  OR : 두 조건 중에서 한 가지만 만족하면 검색 (조건1 OR 조건2)

 

  • WHERE 절의 조건에 해당하지 않을 경우 검색 : NOT

  NOT 조건

 

AND

급여가 2000에서 4000 사이인 사원의 사번, 이름, 급여 출력

SELECT empno, ename, sal FROM emp WHERE sal >=2000 AND sal <= 4000;

 

OR

직급이 CLERK(사무원)이거나, 부서번호가 10번인 사원의 사번, 이름, 직급, 부서번호 출력

SELECT empno, ename, job, deptno FROM emp WHERE job = ‘CLERK’ OR deptno = 10;

 

፠OR과 IN은 경우에 따라 대체하여 사용 가능.

 

NOT

부서번호가 20번이 아닌 사원의 사번, 이름, 부서번호 출력

SELECT empno, ename, deptno FROM emp WHERE NOT depno = 20;

 

NOT IN 연산

부서번호가 10, 20번이 아닌 사원의 사번, 이름, 부서번호 출력

SELECT empno, ename, deptno FROM emp WHERE deptno NOT IN (10,20);



NOT LIKE 연산

이름에 A를 포함하지 않는 사원의 사번, 이름, 부서번호 출력

SELECT empno, ename, deptno FROM emp WHERE ename NOT LIKE ‘%A%’;

 

NOT BETWEEN A AND B 연산

급여가 1000에서 3500 사이에 포함되지 않는 사원의 사번, 이름, 급여 출력

SELECT empno, ename, sal FROM emp WHERE sal NOT BETWEEN 1000 AND 3500;

 

IS NULL, IS NOT NULL

  • 컬럼값이 NULL인지, 아닌지를 비교하는 연산자

  • 관리자(mgr)가 없는(NULL) 사원의 사번, 이름, 관리자 출력

SELECT empno, ename, mgr FROM emp WHERE mgr IS NULL;

 

፠NULL 값은 = 연산자가 아니라 IS NULL 연산자를 사용해야만 비교가 가능.

 

수당을 받는 모든 사원 출력

SELECT empno, ename, comm FROM emp WHERE comm IS NOT NULL;



ORDER BY 절

  • 쿼리 결과의 순서를 다시 정렬하기 위해 사용하는 절

 

SELECT *|컬럼명 FROM 테이블명 WHERE 조건절 ORDER BY 기준컬럼명 [ASC | DESC];

 

기준 컬럼명 : 정렬하기 위한 기준 컬러명

(동일 값을 처리하기 위하여 여러 컬럼을 작성할 수 있음)
ASC : 오름차순(생략가능, default값)

DESC : 내림차순

 

ORDER BY 절 : 숫자 정렬

  • 사원의 사번, 이름, 급여를 출력(급여기준 오름차순)

SELECT empno, ename, sal FROM emp ORDER BY sal; #default 값으로 오름차순

            SELECT empno, ename, sal FROM emp ORDER BY sal DESC; #내림차수

 

ORDER BY 절 : 문자열 정렬

  • 사원의 사번, 이름, 급여를 출력(이름기준 오름차순)

SELECT empno, ename, sal FROM emp ORDER BY ename;

 

ORDER BY 절 : 날짜 정렬

  • 사원의 사번, 이름, 입사일을 출력(입사일이 가장 최근인 사원 순)

SELECT empno, ename, hiredate FROM emp ORDER BY hiredate DESC;

 

ORDER BY 절 : 여러 컬럼값 정렬

  • 사원의 사번, 급여, 이름 출력

(급여기준 내림차순, 급여가 같으면 이름기준 오름차순)

SELECT empno, sla, ename FROM emp ORDER BY sal DESC, ename ASC;

SQL 주요함수 1 - 숫자함수

DUAL 테이블

: SELECT 절에 기술할 테이블이 없을 경우 사용하는 Dummy Table

 

언제 사용할까?

-(Q) 간혹, 상황에 따라 쿼리 작업에서 연산식만 사용하는 경우가 있다.

예를 들어, 10+30 결과를 구하기 위하여 쿼리를 작성한다면?

-SQL > SELECT 10+30 FROM ??????;

 

(?) 10 + 30 연산은 테이블 없다.

-> 실행되려면 테이블이 있어야 한다.

 

ROUND(반올림) 함수

: 지정한 자리 수 이하에서 반올림한 결과를 구해주는 함수

형식 : ROUND(숫자, n) n : 반올림 자릿수

반올림자리

반올림 방법

  • 반올림자리(n)가 0 또는 양수이면, n+1 위치에서 반올림

  • 반올림자리(n)가 음수이면, n위치에서 반올림

 

소수점 이하 두번째 자리에서 반올림

SELECT ROUND(46.593, 2) FROM DUAL; 결과 46.59

 

-1은 일의 자리에서 반올림

SELECT ROUND(46.593, -1) FROM DUAL; 결과 50

 

TRUNC(버림) 함수

: 지정한 자리 수 이하에서 버린 결과를 구해주는 함수

형식 : TRUNC(숫자, n) n : 버림 자릿수

버림자리

버림 방법

  • 버림자리(n)가 0 또는 양수이면, n+1 위치에서 버림

  • 버림자리(n)가 음수이면, n 위치에서 버림

 

소수점 이하 두 번째 자리에서 버림

SELECT TRUNC(46.593, 2) FROM DUAL; 결과 46.59

 

-1은 일의 자리에서 버림

SELECT TRUNC(46.593, -1) FROM DUAL; 결과 40



MOD(나머지) 함수

: 나누기 연산을 한 후에 구한 나머지를 결과로 돌려주는 함수

형식 : MOD(컬럼| 숫자, 나누기값)

 

10번 부서 사원의 급여를 100으로 나눈 나머지 출력

SELECT MOD(sal, 100) FROM emp WHERE deptno = 10;



SQL 주요함수 2 - 문자함수

UPPER(대문자), LOWER(소문자) 함수

: 소문자는 대문자로, 대문자는 소문자로 변환하여 출력하는 함수

 

20번 부서 사원의 모든 이름을 모두 소문자로 변경하여 출력하는 쿼리를 작성하시오.

SELECT LOWER(ename) FROM emp WHERE deptno = 20;

 

INITCAP 함수

: 단어의 첫글자를 대문자로 변환하여 출력하는 함수

 

사원 이름의 첫 글자를 대문자로 출력하는 쿼리를 작성하시오

SELECT INITCAP(ename) FROM emp;

 

LENGTH 함수

: 문자열의 길이를 구하여 출력하는 함수

 

사원 이름이 몇 글자인지 출력하는 쿼리를 작성하시오.

SELECT ename, LENGTH(ename) FROM emp;

 

INSTR 함수

: 특정 컬럼 또는 문자열에서 지정 문자의 위치를 반환하는 함수

형식 : INSTR(컬럼|문자열, [검색할 시작위치], [검색문자 순서])

 

-SQL>SELECT INSTR(‘welcome to oracle’, ‘o’) FROM DUAL; 결과 5

           SELECT INSTR(‘welcome to oracle’, ‘o’, 6) FROM DUAL; 결과 10

           SELECT INSTR(‘welcome to oracle’, ‘o’, 3, 3) FROM DUAL; 결과 12

 

SUBSTR 함수

: 특정 컬럼 또는 문자열에서 지정한 일부분을 추출하여 반환하는 함수

형식 : SUBSTR(컬럼|문자열,m,[n]) //m : 시작워치, n : 추출문자개수

*n이 생략되면 m 위치에서 문자열 끝까지 추출

 

SQL>SELECT SUBSTR(‘welcome to oracle’, 4, 3) FROM DUAL; 결과 com

          SELECT SUBSTR(‘welcome to oracle’, 10) FROM DUAL; 결과  oracle




LPAD, RPAD 함수

: 오른쪽(왼쪽) 정렬 후, 지정 문자를 왼쪽(오른쪽)에 채우는 함수

형식 : LPAD(컬럼|문자열, m, ‘c’), RPAD(컬럼|문자열,m, ‘c’)

       m: 자리수, c: 채울문자

 

SELECT LPAD(‘oracle’,10,’*’), RPAD(‘oracle’,10,’*’) FROM DUAL:

                         ****oracle                 oracle****

 

LTRIM, RTRIM 함수

: 왼쪽(오른쪽) 지정 문자가 연속이면 지정 문자를 삭제하는 함수

형식 : LTRIM(컬럼|문자열, ‘c’), RTRIM(컬럼|문자열, ‘c’) c: 삭제문자

 

SELECT LTRIM(‘****oracle’, ‘*’), RTRIM(‘oracle****’,’*’) FROM DUAL;

                            oracle                             oracle

 

TRIM 함수

: 양쪽에 지정 문자가 연속이면 지정 문자를 삭제하는 함수

형식 : TRIM(‘c’ from 컬럼|문자열)

 

SELECT TRIM(‘*’ from ‘***oracle****’) FROM DUAL;

결과 : oracle




SQL 주요함수 3 - 날짜함수

날짜 함수
: 날짜 데이터형에 사용, 대부분 일 단위로 계산(기본표현 : 년/월/일)

 

SYSDATE 함수

: 시스템에 저장된 현재 날짜와 시간을 반환하는 함수

 

SELECT SYSDATE FROM DUAL; 기본적으로 날짜만 출력하고 시간은 표시되지 않음.

 

날짜 연산

: 날짜 형 데이터에도 더하기나 빼기와 같은 연산이 가능함

 

SYSDATE+1(내일 날짜), SYSDATE-1(어제 날짜)

SELECT SYSDATE+1, SYSDATE -1 FROM DUAL;

 

날짜 연산

  • 20번 부서 사원들의 현재까지 근무 일수를 출력하는 쿼리를 작성하시오.

SELECT ename, hiredate, SYSDATE-hiredate FROM emp WHERE deptno = 20;

 

፠ 날짜타입에는 연월일뿐만 아니라, 시분초까지도 저장되어 있음. 소수점 이하의 숫자는 하루가 되지 못한 시간을 의미.

MONTHS_BETWEEN 함수

: 날짜와 날짜 사이의 개월 수를 구하는 함수

형식 : MONTHS_BETWEEN(최근날짜, 이전 날짜)

 

  • 20번 부서 사원들의 현재까지 근무 개월수를 출력하는 쿼리를 작성하시오.

  • SELECT ename, hiredate, MONTHS_BETWEEN(SYSDATE, hiredate) FROM emp WHERE deptno = 20;

 

ADD_MONTHS 함수

: 지정한 개월 수를 더한 날짜를 구하는 함수

형식 : ADD_MONTHS(날짜, 더할 개월수)

 

  • 20번 부원 사원들의 입사일자에서 6개월 후 일자를 구하는 쿼리를 작성하시오.

  • SELECT hiredate, ADD_MONTHS(hiredate, 6) FROM emp WHERE deptno = 20;

 

LAST_DAY 함수

: 해달 날짜가 속한 달의 마지막 날짜를 반환하는 함수

형식 : LAST_DAY(날짜)

 

  • 20번 부서 사원들의 입사한 달의 마지막 날을 구하는 쿼리를 작성하시오

SELECT hiredate, LAST_DAY(hiredate) FROM emp WHERE deptno = 20;

 

NEXT_DAY 함수

: 해당 날짜를 기준으로 명시된 요일에 해당되는 날짜를 반환하는 함수

형식 : NEXT_DAY(날짜, 요일)

  • 현재 날짜를 기준으로 최초로 돌아오는 월요일 날짜를 구하는 쿼리를 작성하시오.

SELECT NEXT_DAY(SYSDATE, ‘월’) FROM DUAL;

 

SQL 주요함수 4 - 형변환함수

형 변환 함수

: 숫자, 문자, 날짜의 데이터 형을 변환해야 하는 경우에 사용하는 함수

 

TO_NUMBER : 문자 데이터 -> 숫자 데이터

TO_CHAR : 숫자 데이터 -> 문자 데이터

TO_DATE : 문자 데이터 -> 날짜 데이터

 

TO_DATE 함수 : 문자 -> 날짜

  • 날짜형은 날짜(년월일)와 시간(시분초)에 대한 정보를 저장

  • 오라클 기본 날짜 형식 : YY/MM/DD

형식 : TO_DATE(‘날짜표현문자열’, 날짜_시간포맷)

 

 

TO_DATE 함수 : 문자 -> 날짜

  • ‘2020-01-20’ 날짜형식으로 표현된 문자 데이터를, 날짜 데이터(20/01/20)로 출력하는 쿼리를 작성하시오

SELECT TO_DATE(‘2020-01-20’, ‘YYYY/MM/DD’) FROM DUAL;

 

TO_CHAR 함수

형식 : TO_CHAR(숫자|날짜, 형별포맷)

 

 

  • 현재 날짜와 시간을 출력하는 쿼리를 작성하시오.

SELECT TO_CHAR(SYSDATE, ‘YYYY/MM/DD, HH24:MI:SS’), FROM DUAL;

 

TO_CHAR 함수 : 숫자 -> 문자

  • 20번 부서의 사원 급여를 6자리로 바꾸고, 앞에 $ 또는 지역통화를 붙여 출력하느 쿼리를 작성하시오.(예 : $2,200, \2,200)

SELECT ename, TO_CHAR(sal,’$999,999’), TO_CHAR(sal,’L999,999’) FROM emp WHERE deptno = 20;

TO_NUMBER 함수 : 문자 -> 숫자

  • 숫자형식으로 표현된 문자열을 숫자로 변환

형식 : TO_NUMBER(‘문자숫자’)

SELECT TO_NUMBER(‘123’), TO_NUMBER(‘12.3’) FROM DUAL;

 

Chapter 3.5 connection-oriented transport: TCP

Computer Networking : A Top Down Approach 7th Edition, Global Edition Jim Kurose, Keith Ross

Point-to-Point

TCP는 연결지향(Connection-oriented) 프로토콜이다. 즉, 1대1 연결 상태를 유지하여 통신하는 것을 말한다.

이는 point-to-point 로써, 한명의 송신자에는 한명의 수신자만 있음을 의미한다.

1대 다수의 통신인 multicasting이 불가능하다.

 

reliable, in-order byte stream

tcp는 메시지의 경계(또는 구분)가 없다.

신뢰적인 순서 보장 스트림이 있다(reliable, in-order byte stream)

즉, Application에서 준 데이터는 순서대로 정확히 전달된다.

 

pipelined

TCP 혼잡(congestion)과 flow control(흐름 제어)에 따라 Window Size를 설정한다.

 

full duplex data

동일한 연결에서 양쪽에서 보내는 것과 받는 것이 동시에 가능하다.

-전이중 방식

MSS(Maximum Segment Size) : segment에 담길 수 있는 최대 data 양

Link layer의 가장 큰 frame에 의해 결정된다.

- Segment에서 layer data의 크기 제한

- 사이즈가 큰 파일을 전송할 때, MSS 크기로 파일을 자름.

 

Connection-oriented

3-way handshake를 수행하며, 상호 간에 통신을 초기화 하는데

Window Size, buffer 할당, 순서번호(seq#) 등이 결정된다.

양 side에 3개의 요소가 생긴다.

( buffer, variable, socket connection)

 

 

flow controlled

송신자는 수신자가 받을 수 있을 만큼만 보내고 receiver가 전송량을 통제한다.


TCP segment structure

source port, dest port : 출발지, 목적지 포트로 다중화/역다중화에 사용

---

sequence number : 순서번호 필드

---

acknowledgement number : 확인 응답번호 필드 ( 500 일 경우, 499까지는 받았다는 뜻)

---

URG : 일반적으로 사용하지 않는다(generally not used)

ACK

PSH : 일반적으로 사용하지 않는다(generally not used)

R(RST) : reset

S(SYN) : sync

F(FIN) : finish

receive window :수신측이 갖고 있는 buffer size. flow control 시 사용

---

checksum : 체크섬 오류 검출

Urg data pointer : 현재 사용하지 않음

---

otions

---

application data


TCP seq numbers, ACKs

seq number : Segment의 첫 번째 byte의 stream에서의 byte 순서 번호를 의미.

   예) 데이터 스트림이 500,000byte이고, MSS가 100일 경우 500개의 Segment가 생성.

        이 때, 첫 번째 Segment의 seq number은 0,

        두 번째 세그먼트의 순서번호는 1000

   

ACKs : 다음에 받을 것으로 예상되는 seq number

         -TCP는 오직 첫 missing byte만을 ACK 하기 때문에 Cumulative ACK 가 가능하다.

  예) 수신자가 0~535byte를 포함하는 Segment와 900~1000byte를 포함하는 Segment를 수신받고

       536~899byte는 수신 받지 못했을 경우, 536번째 byte를 수신하기 위해

      다은 세그먼트 확인 응답 번호 필드(Acknowledgement num)를 536으로 지정한다.

 

Q. 순서가 틀린 Segment를 수신한 경우는?

- 특별히 정해둔 규칙이 없음.(프로그래머의 마음대로)

- 즉시 버리거나 ,buffering 하는 방법이 존재

 

 

위 그림에서 호스트 A는 seq num가 42, 호스트 B의 seq num은 79이다.

호스트 A는 42번째 byte를 보내면서 79번째 byte를 호스트 B에게 요구한다.

호스트 B는 79번째 byte를 보내면서 다음으로 원하는 byte인 43번째 byte를 호스트 A에게 요구한다.

 

마지막에 data가 없는데 Seq num을 가지는 경우는 TCP header에는 seq number field를 채워야하기 때문에

ACK로 온 number을 Seq number에 넣어 보낸 것이다.

 


TCP round trip time, timeout

tcp의 timeout은 어떻게 설정할까?

- RTT(round trip time) 보다는 길어야 한다.

- 너무 짧을 경우 : 불필요한 재전송이 일어난다.

- 너무 큰 경우 : Segment 손실에 대한 대응이 늦어진다.

 

RTT(round trip time)의 측정 방법

- Sample RTT : segment가 보내진 후로부터 해당 segment의 ACK가 도착하기까지 걸린 RTT.

재전송된 Packet은 RTT를 측정하지 않는다. 

Estimated RTT는 매우 smooth하게 변경된다. 변경폭이 크지 않다.

Sample RTT를 통해 평균을 내어 Estimated RTT를 측정한다.

 

Exponential weighted moving average를 사용한다.

 

a(알파)값은 대략 0.125로 잡는다.

 

RTT 추청지 예제

timeout 설정

- Estimated RTT보다 약간의 여유값을 더한 값으로 설정

- Dev RTT - Sample RTT 와 Estimated RTT의 차에 의해 결정된다.

   : Sample RTT가 Estimated RTT로부터 얼마나 벗어나는지에 대한 예측

이때, b(베타)의 권장값은 0.25이다.

 

이제 이 Estimated RTT와 Dev RTT를 이용해 timeout interval을 계산한다.

 

실제 timeout 설정

 

Chapter 3.4 principles of reliable data transfer

Computer Networking : A Top Down Approach 7th Edition, Global Edition Jim Kurose, Keith Ross

Pipelined protocols

이전 포스트에서 rdt 방식은 stop-and-wait 으로 진행됨으로 굉장히 효율이 떨어진다는 것을 알았다.

효율을 높이기 위해서 파이프라이닝 방식을 사용한다. 

컴퓨터 구조를 공부한 적이 있는 사람이라면 이 그림이 익숙할 것이다.

 

파이프라이닝이란 무엇일까? 단순히 말해 여러 일을 동시에 처리하는 것이다.

4명의 사람이 자신의 옷을 세탁한다고 가정하자. 

 

세탁기에 옷을 넣고 세탁 -> 건조기에 옷을 말림 -> 옷을 갠다 -> 옷장에 보관

 

위 그림에서 이 하나의 과정은 한 번 하는데 2시간이 걸린다.

A, B, C, D 라는 사람이 이 일을 각각 하나씩 하는데 서로의 작업이 전부 끝날 때까지 기다렸다가

자신의 일을 한다고 가정하면 저녁 6시에 시작한 일이 무려 새벽 2시가 되어서 끝이 난다.

 

이와 반대로 앞 사람이 끝난 작업을 다음 사람이 바로 하게 되면 

모든 작업이 9시 30분에 끝나게 되니 얼마나 효율적인가?

 

이것이 바로 파이프라이닝이다. 

 

한번의 한 개씩 패킷이 목적지에 도착하면 목적지로부터 돌아오는 ACK를 기다리지 말고

여러 패킷을 전송할 수 있도록 하는 것이다.

 

파이프라이닝을 이용하여 이전보다 이용률이 무려 3배나 좋아진다.

 

하지만 파이프라이닝을 사용하려면 다음 사항을 고려해야 한다.

  • 순서 번호(sequence number) 범위의 증가 : 여러 패킷을 보낼 수 있게 됨으로써 0과 1 만으로는 부족
  • 버퍼(buffer)의 필요 : 송신측과 수신측은 여러 패킷을 담을 수 있는 버퍼가 필요
  • 파이프라인의 대한 오류 : 파이프라인에서 발생하는 패킷 손실 , 지연 패킷에 대한 처리 방식이 필요

이 고려 사항들은 어떻게 해결해야 할까?


GBN(Go-Back-N) : N에서부터 다시

GBN 프로토콜은 수신자 측에서 지금까지 성공적으로 받은 패킷 순서 번호에 대한 ACK를 전송하며,

순서에 맞지 않는 패킷은 성공적으로 수신한 것으로 간주하지 않는다.

따라서 송신자는 ACK를 받지 못한 가장 오래된 패킷부터 다시 재전송하게 된다.

 

왼쪽에서 오른쪽으로 쌓이는데 가장 왼쪽에 있는(=가장 오래된) 노란색 패킷부터 재전송한다.

이때 이 패킷들은 최대 허용수(N=window size) 보다 크지 않아야 한다.

 

  • 수신자는 누적된(cumulative) ACK만 전송 (수신된 패킷들의 순서번호 사이에 갭이 있으면 ACK는 응답하지 않음)
  • 수신자는 비순차(out of order) 패킷으로 버퍼링하지 않는다.
  • 송신자는 ACK받지 못한(문제가 생긴) 가장 오래된 패킷부터 모두 재전송 (타이머가 1개)

 

위 그림의 sender에게는 4개의 저장 공간이 있다.

처음에 sender는 패킷을 pkt0부터 pkt3 까지 총 4개를 보내고 ACK를 대기한다.

 

pkt2의 경우, 중간에 손실이 있어서 receiver는 이를 받지 못했기 때문에 ACK2를 보내지 않고

ACK1을 보내어 자신이 pkt2를 제대로 받지 못했음을 알린다. 

 

더보기

※이전까지 순서 번호가 0과 1만 있었는데 이제 2도 생겼음을 눈치챘는가?

앞에서 pkt0, pkt1의 긍정응답인 ACK0과 ACK1은 슬라이딩 되어 다음 패킷인 pkt4와 pkt5를 보낸다.

 

앞에서 pkt2를 받지 못했으니 이후의 패킷인 pkt3, pkt4, pkt5는 잘 도착하여도 이를 버리고(discard)

sender에게 ACK3 ACK4 ACK5 가 아니라 모두 ACK 1을 보낸다.

 

즉 pkt2가 다시 제대로 receiver에게 전달되어 ACK2가 sender에게 가야만 뒷 작업인

pkt3, pkt4, pkt5의 패킷을 받을 수 있는 것이다.

 

패킷 pkt3, pkt4, pkt5(후배님들)는 자신들보다 먼저 보내졌던 pkt2(선배님)을 받지 못하였다고

온전히 받아졌음에도 불구하고 버려졌다(discard).

 

굉장히 비효율적이지 않은가?

이것을 해결하기 위해 SR 이 등장했다.


SR(Selective Repeat) : 선택된 것만 다시

SR은 받는 쪽에도 저장 공간을 만드는 것이다.

따라서 불필요한 재전송 즉, 이미 온전히 받은 패킷의 재전송을 피할 수 있다.

 

(a)는 sender의 저장 공간, (b)는 receiver의 저장 공간이다.

receiver의 저장 공간을 보면 sender로부터 문제 없이 도착한 패킷은 자주색,

그렇지 못한 패킷은 회색으로 표시가 되어 있다.

 

동작이 어떻게 이루어지는지 살펴보자.

 

아까와 마찬가지로 sender는 패킷을 pkt0부터 pkt3 까지 총 4개를 보내고 ACK를 대기한다.

pkt2가 손실이 일어나 receiver는 이를 받지 못했지만 

pkt3를 받았을 때 순서 번호 3에 맞춰 ACK3를 보낸다. 

pkt4와 pkt5를 받은 receiver 또한 ACK4 ACK5를 보낸다.

pkt2의 긍정응답인 ACK2를 대기하고 있던 타이머가 초과(time out)되어 pkt2를 재전송한다.

 

이러한 SR에도 문제점이 있는데 아래를 살펴보자


이 그림에서 pkt0, pkt1,pkt2의 긍정응답인 ack0, ack1, ack2가 sender에게 가는 도중 손실이 되었다.

타임 아웃 이후에 pkt0을 재전송하게 된다면

이것이 순서번호가 0인 첫번째 패킷이 재전송된 것인지,

아니면 이동한 슬라이드 안의 순서번호가 0인 새로운 패킷이 온 것인지

알 방법이 없다.

 

이를 해결하기 위해선 위에서 나온 N(=window size)의 크기 조절이 중요하다.

N은 sender의 순서번호 공간 크기의 절반보다 작거나 같아야한다.

 

예를 들어 순서번호가 0,1,2,3 총 4개라면 N은 1~3의 크기를 가져야 한다.

 

Chapter 3.4 principles of reliable data transfer

Computer Networking : A Top Down Approach 7th Edition, Global Edition Jim Kurose, Keith Ross

슬램 덩크

 

데이터를 주고 받는 과정에서는 상대방에게 잘 전달되었는지가 단연 중요하다고 할 수 있다.

 

만약 제대로 통신이 되지 않는 채널, 즉 비신뢰적인(unreliable) 채널에서 데이터를 전송한다면

전송 도중에 에러가 나거나 분실, 순서가 지켜지지 않는 등의 문제가 발생할 수도 있다. 

위의 문제를 해결한다면 '신뢰성 있다' 라고 할 수 있을 것이다.

 

데이터 전송에서는 신뢰적인 데이터 전송(reliable data transfer)이 중요하며,

Transport layer의 주된 역할이 바로 신뢰성이 있는 데이터의 전송이다.

 

 

 

 

위 그림 (a)에서처럼 데이터를 transport layer에 있는 reliable(신뢰성 있는) 채널을 통해 목적지 프로세스까지

별다른 문제없이 데이터를 전송할 수 있을 것이다.

 

허나, 실제로 이를 구현하는 측면에서 보았을 때, (b)와 같이 transport layer 아래 계층(그림에서는 따로 표시가 없지만 이것은 Network layer을 말함)에는 unreliable(신뢰하지 못하는) 채널이 있으므로

신뢰성이 있는 채널을 구현하기가 어려워진다.

 

그렇다면 신뢰성 있는 채널을 만들려면 어떻게 해아할까?


신뢰적인 데이터 전송 프로토콜을 만들기 위해서는 가장 간단한 상황부터 복잡해지는 상황까지의 경우를 생각해보자.

 

  • 완벽하게 신뢰적인 채널에서 신뢰적인 데이터 전송 => rdt1.0
  • 비트 오류가 있는 채널에서 신뢰적인 데이터 전송 => rdt2.0 , (rdt2.0의 수정된 버전 : rdt2.1 , rdt2.2)
  • 비트 오류 & 손실이 있는 채널에서 신뢰적인 데이터 전송 =>rdt3.0

rdt라는 단어가 계속해서 쓰이는데, 이는 reliable data transport 의 약자이다.

위 상황을 설명하기 위해 우선 단방향 전송이라고만 가정한다.

또한 송신자와 수신자의 동작을 유한 상태 머신(Finite State Machines : FSM)으로 표현할 것이다.


rdt1.0 : 오류 없는 경우

우선, 첫번째 경우인 rdt1.0을 보자.

 

송신자와 수신자가 분리된 유한 상태 머신을 가지고 있다.

 

데이터 전송에 에러가 발생하지 않는 가정 하의 전송이기 때문에 그저 간단한 과정만 거친다.

 

Sender

  1. 송신측(sender)의 rdt_send 함수가 상위 계층에서 오는 데이터를 받음.
  2. make_pkt 함수가 데이터를 패킷으로 만들고 packet 변수에 저장.
  3. udt_send 함수가 packet 변수에 담긴 패킷을 채널로 내려보내면서 전송.

Receiver

  1. rdt_rcv 함수가 하위 채널로부터 패킷을 수신한다.
  2. extract 함수로 패킷에 있는 데이터를 추출해낸다.
  3. deliver_data 함수로 추출한 데이터를 상위 계층으로 전달한다.

rdt1.0의 경우 하위 채널이 완전히 신뢰할 수 있기에 수신자 측에서 잘 받았다고 피드백을 할 필요가 딱히 없다.

 


rdt2.0 비트 오류가 있는 경우

rdt1.0 보다 복잡해졌기 때문에 (비트 오류가 있음) 2.0이라고 불린다. 

우선 rdt2.0을 설명하기 전에 현실세계에서 일어날 법한 전화 속 대화를 생각해보겠다.

 

소풍 가고 싶다... 코로나 ㅅㅂ

A : "오늘 오후 1시에 공원에서 만나는 거 알지?"
B : "알지! 뭐 챙겨야 하는 거 있어?"
A : "돗자리 들고와!"

            -잡음 발생-

B : "뭐 들고 오라고?"
A : "돗자리!"
B : "알았어! 돗자리 챙길께~"

위 대화에서 B는 A가 말한 내용을 정확하게 듣지 못하여(=수신에 오류가 남) 무엇을 들고

오라고 하는지 다시 한번 알려달라는 재전송을 요청했다.

여기서 "뭐 들고 오라고?" 는 A에게 NAKs(negative acknowledgements) 부정 확인 응답을 보낸 것과 같다.

 

NAKs를 받은 A는 "돗자리!" 라고 다시 말해주고 그제서야 자신이 돗자리를 챙겨야 한다는 것을 깨달은 B는 A에게

"알았어! 돗자리 챙길께~" 라는 ACKs(acknowledgements) 긍정 확인 응답을 보낸다.

 

통신에서 이렇게 재전송을 기반으로 하는 신뢰적인 프로토콜을 

자동 재전송 요구 프로토콜 ARQ(Automatic Repeat reQuest)라고 한다.

 

위 대화로 계속 설명을 이어나가겠다.

 

ARQ 프로토콜이 이루어지려면 우선, B가 제대로 듣지 못했다는 것(오류가 발생했다는 것)

스스로 파악할 수 있어야 한다.

 

예를 들어 돗자리 들고 오라는 A의 말을 잡음으로 인해 잘못 들었음에도

"대충 잠자리 채 들고 오란 말인가?" 라고 생각해(=오류 검출 능력이 없음) 돗자리가 아닌 잠자리 채를 들고 간다면

아마 도시락을 싸온 A에게 싸대기를 맞을 것이다.

 

통신에서는 이러한 오류가 발생했음을 검출해내기 위해 헤더에 설정한 체크섬(checksum)을 사용한다.

자신이 정확하게 듣지 못했음을(=오류가 발생했음을) 파악한 B는 A에게 다시 한번 말해달라고 요청한다.

이때, 수신자인 A는 B의 "뭐 들고 오라고?" 라는 피드백을 받을 수 있어야 한다.

그래야 A가 "제대로 못들었구나" 라고 생각해 다시 한번 말해 줄 수 있기 때문이다. (재전송)

 

rdt1.0과 달리 rdt2.0에서 데이터 송신 측인 sender에서 checksum이라는 단어가 보일 것이다.

 

Sender

  1. 송신측(sender)의 rdt_send 함수가 상위 계층에서 오는 데이터를 받음.
  2.  sndpkt 라는 변수에 make_pkt 함수를 이용해 체크섬이 포함된 패킷을 담음. (receiver가 오류를 파악할 수 있게)
  3. udt_send 함수가 sndpkt 변수에 담긴 패킷을 채널로 내려보내면서 전송.
  4. 이후 상태 변화가 일어나 receiver 측으로 부터 ACKs 나 NAKs가 올 때까지 대기한다. (stop-and-wait) 중요
  5. NAKs 를 받았을 경우 udt_send 함수로 다시 재전송을 하고 ACKs 받으면 1번 상태로 돌아간다. (둘 중 하나를 받기 전까지 4번에서 계속 대기하고 있음)

 

Receiver

  1. rdt_rcv 함수가 하위 채널로부터 패킷을 수신하는데 corrupt 함수로 오류를 확인해서 오류가 발생했을 시 sender에게 NAKs를 보낸다.
  2. 오류가 발생하지 않았을 경우에는 extract 함수로 패킷에 있는 데이터를 추출해낸다.
  3. deliver_data 함수로 추출한 데이터를 상위 계층으로 전달한다.
  4. sender에게 ACKs 를 보낸다. ("무사히 받아서 처리했다 ><")

어려운게 있는가? 


rdt2.1

그런데 만약 recevier가 sender에게 보낸 NAKs 나 ACKs가 손상이 나면 어떻게 할까?

NAKs도 ACKs도 오지 않는 상황이라면 sender는 이를 계속 기다리는 일도 발생할 것이다.

중복으로 송신하면 sender가 중복으로 수신하는 상황도 있을 것인데...

 

이를 해결하기 위해 rdt2.0의 수정된 버전인 rdt2.1에서는 데이터 패킷에 순서번호(sequence number)를 추가했다.

순서번호를 추가하여 뭐가 어떻게 달라지는지 유명한 애니메이션인 스폰지밥으로 예를 들어보자.

 

주문을 받는 징징이

징징이 : 게살버거 244개 주문 들어왔어
스폰지밥 : 주문 확인! 게살버거 244개 만들께!

-주방이 시끄러워서 데스크까지 전달이 안됨-

징징이 : 스폰지밥! 게살버거 244개 주문 들어왔어!!
스폰지밥 : (아까랑 똑같은 주문인데) 그럼 게살버거를 총 488개나 만드는거야? 와~우

sender인 징징이는 receiver에 해당하는 스폰지밥에게 데이터(게살버거 244개 주문)를 전달하였고

스폰지밥이 있는 주방에서 주문 확인을 받았다는 대답을 들으려 하였다.

하지만 가게가 너무 시끄러워서 주문 확인(ACKs)이라는 대답을 듣지 못한 징징이는 한번 더

똑같은 데이터(게살버거 244개)를 보냈고 이를 두 번이나 들은 스폰지밥은 개살버거를 손님이 주문한 양보다

더 많이 만드는 사고를 저지를 수 있다.

 

열심히 만드는 스폰지밥

이렇게 NAKs 나 ACKs를 받지 못한 sender는 계속 대기하지 않고 똑같은 데이터를 한번 더 

receiver에게 전달한다. 이를 받은 receiver은 중복으로 동일한 데이터를 받게 되는데 이 데이터가

재전송으로 인한 중복 패킷인지 새로운 패킷인지를 확인할 때 위에서 언급한 순서 번호가 사용된다.

 

순서 번호는 0과 1을 번갈아가면서 사용하는데, 만약 같은 순서 번호가 연속으로 수신 된다면 해당 데이터는

재전송으로 인한 패킷임을 확인할 수 있는 것이다!

 

              0-> 1-> 1-> 1-> 0->1 -> 0 -> 0->0 

 

 

rdt2.1 의 sender

  Sender

수신된 ACKs/NAKs의 오류 여부에 대한 상태가 추가되어 rdt2.0 보다 상태 수가 2배 증가하므로

총 4개의 상태를 가진다.

 

 

rdt2.1의 recevier

Receiver

들어온 패킷의 중복 여부를 확인하고 마지막으로 보낸 ACKs/NAKs를 sender가 잘 받았는지 확인한다.


위에서 설명한 rdt2.1과 기능은 동일하나 NAKs를 사용하지 않고 ACKs만 사용하는 모델이 바로

rdt2.2

NAKs를 보내는 대신, 가장 최근에 잘 받은 패킷에 대한 ACKs를 보냄으로써

NAKs를 보내는 것과 같은 기능을 수행할 수 있다.

rdt2.2

위 그림의 sender의 FSM에서 isACK(rcvpkt,1) 와 isACK(rcvpkt,0)에 빨간색으로 강조가 된 것을 볼 수 있다.

즉, ACKs가 제대로 와야 다음 상태로 갈 수 있는 것이다.

 

"ㅅㅂ 무슨 말이야?" 라고 생각하면 밑 그림을 보자.

 

친절한 그림 설명^^

어려운게 있는가? 


마지막으로 비트 오류 & 손실이 있는 채널에서의 신뢰적인 데이터 전송은 어떻게 해야 할까?

rdt3.0 : 비트 오류와 손실이 있는 경우

비트의 손실이 추가되었다. 비트의 손실은 어떻게 할까? 

 

별 것 없다. 마찬가지로 손실이 일어난 패킷을 또 다시 보내면 된다!

또 다시 보내는 것은 위에서 계속해서 기능을 추가했던 일이 아니였던가?

 

타임 아웃!

rdt3.0에서는 또 하나의 기능을 더 추가하는 데 그것은 바로 타임 아웃 타이머이다.

 

rdt 2.2에서 쉽게 설명한 그림 설명을 다시 보자.

비트 오류가 일어났다면 이를 감지하고 ACK0을 전달하여 다시 요청을 했다.

그런데 만약 ACK0이라는 데이터의 비트가 손실이 일어나면 어떻게 할까?

 

ACK loss

 

sender가 이를 무한정 기다리는 일이 생간다. 

그렇기에 일정 시간이 지나도 ACK 응답이 오지 않으면 그냥 새로 한번 더 보내는 것이다!

물론 처음에 sender가 보낸 hello 1 의 패킷이 receiver에게 가는 도중 손실이 일어나도

ACK 0을 보내지 못하는 것은 같으므로 시간 초과가 되면 어쨋거나 sender은 한번 더 똑같은

패킷인 hello 0을 보낼것이다.

 

그런데 만약 receiver가 보낸 패킷이 손실된 것이 아니라 어떤 이유로 시간 초과보다 늦게

도착하는 경우는 어떻게될까?

 

이미 패킷이 중복됬을 경우를 처리하기 위한 순서 번호(sequence number) 기능이 있으니 

문제 없이 작동한다!


rdt 3.0 까지 발전시켜나감으로써 신뢰성 있는 통신이 가능해졌다. 

이론적으로 보았을 때도 굉장히 잘 작동할 것 같다. 

뭐 잘 작동하는 건 좋다 이거야 그런데 뭔가 굉장히 느릴꺼 같지 않은가?

 

이유는 전송 후 대기(stop-and-wait) 하는 방식이기 때문이다.

 

예를 들어보자. 

 

광활한 미국의 대륙이다. 황단 시 4000~4500km의 거리를 가야한다.

미국 서부에서 동부로 통신을 하려고 한다.

  • 두 지점 사이의 RTT : 30msec
  • 1Gbps 전송률(R)을 가진 채널로 연결
  • 헤더와 데이터를 포함하여 패킷 당 1000byte(=8000비트) 의 패킷크기(L)를 가진 패킷을 전송

※RTT : Round Trip Time으로 패킷이 목적지로 도착하고, 목적지에서 보낸 ACK가 출발지까지 돌아오는데 걸리는 시간

 

위와 같은 상황에서 8000비트를 미국 대륙의 끝과 끝으로 보내는데 시간이 얼마나 걸릴까?

 

 

계산 결과 0.000008 초가 걸린다.

 

위에서 두 지점 사이의 RTT는 30msec(=0.03초) 라고 하였음으로 이 시간도 더하면

8000비트를 보낸 출발지가 목적지가 보낸 ACK 를 받으려면 

30.008msec(=0.030008초)가 걸림을 계산할 수 있다.

 

총 30.008msec의 시간 동안 T(=L/R) 0.008msec 의 데이터만 전송한 것이니 이용률을 계산하면

전체 시간의 0.00027이다. stop-and-wait 프로토콜의 문제점은 이처럼 효율이 좋지 않다는 것이다.

 

효율을 높히려면 어떻게 해야할까?

 

ACK가 도착할 때까지 대기하지 않고 여러 패킷을 전송하는 것이다!

 

sidongmen

파이프라인(Pipeline)은 다음 포스트에서 이어서 설명하겠다.

+ Recent posts