===== Intro =====
1.
제 나름대로 구상한 방식입니다
2.
막히면 돌아가고 깊이가 방대하면 포기하고 다음으로!
3.
구성 : 토픽 – 기반기술 학습 – 기반기술 기반 실습(되는데로..) – 최종 프로젝트
===== Overall story =====
1.
1화 = 북한 ip의 구성
2.
2화 =
Torrent 이용중 IP 동작
3.
3화 = 마그넷
링크를 뜯어보고 토렌트가 무엇으로 파일을 식별하는지 이해
4.
4화 =
Tracker는 Peer 목록을 어떻게 알려줄까? (실제
통신)
Step – 0
== InfoHash를 알게되면
Peer는 어떻게 찾는 거지?
지난 글에서 Magnet Link 안에 있는 InfoHash가 무엇인지 살펴 보며 토렌트 네트워크에서 파일은 이름이 아니라
InfoHash 로 식별되는 사실도 확인했는데.. 궁금한점이 생긴다
è InfoHash 를 알게되면 Peer는 어떻게 찾는건데?
토렌트 클라이언트가 무작정 인터넷 전체를 뒤질수 없기 때문에 Tracker 서버에게
물어본다, 그리고 Tracker 서버는 해당 Torrent 를 공유하고 있는 Peer 들의 정보를 반환한다
이번 에피소드에서 Tracker와 실제로 어떤 데이터를 주고받는지
살펴보자
(실제
패킷을 보는 단계까지 해봅시다)
Step – 1
== Tracker란?
Tracker를 간단히 정의하면!
è 이 토렌트를 공유하고
있는 사람들의 명단을 관리하는 서버
지난번부터 사용하고 있는 ubuntu의 infoHash가 Abcdefg12345 이고 만약 참여중인 Peer 가 = 1.1.1.1 2.2.2.2 3.3.3.3 4.4.4.4 라고
하면 Tracker에 InfoHash를 질의하면 Peer정보를 반환한다
Step – 2
== Tracker에게 보내는 첫 메시지
Tracker에 보내는 메시지중 첫번째 메시지를 Announce Request라고 부르며 Client(사용자)가 Tracker에게 보내는 메시지는 다음과 같음
|
GET /announce? info_hash=... peer_id=... port=6881 uploaded=0 downloaded=0 left=123456 event=started |
그리고 이를 url 형태로 붙혀서 보내는데 이런식으로 뒤에 QueryString 형태로 정보가 붙는다
è http://tracker.example.com/announce
이때 파라미터를 살펴보자
|
Info_hash |
지난화에 설명한
InfoHash |
|
peer_id=... |
클라이언트 식별값(-UT2210-abcdefgh1234
= utorrent 식별값) *다양한 Torrent client 가 있음) |
|
port=6881 |
Peer가 연결을
받을 포트 |
|
uploaded=0 |
업로드한 바이트 |
|
downloaded=0 |
다운로드한 바이트 |
|
left=123456 |
남은 다운로드 크기 |
|
event= |
현재 상태 started /
completed / stopped 3가지 상태가 있음 |
이를 기반으로 통신 순서를 정리하면 다음과 같이 진행 된다
è Client ----(Announce) ------>Tracker ------(Peer List) ---->
Client
è 매우 단순함
Step – 3
== Tracker응답은 어떻게 생겼지?
Tracker응답은 JSON이
아니다, 보통 이런 다양한 값을 보내면 응답이 JSON으로
오는 경우가 많은데 (아래 그림처럼 생긴게 JSON 타입)
|
{ "peers":[] } |
토렌트는 오래된 프로토콜이라 Bencode라는 자체 포맷을 사용한다!
è Bencode = 토렌트에서 사용하는 직렬화 포맷 (아래를 보자)
|
타입 |
예시 |
의미 |
|
문자열 |
4:spam |
Spam |
|
숫자 |
i123e |
123 |
|
리스트 |
l 4:spam 4:eggs e |
["spam","eggs"] |
|
딕셔너리 |
d 3:cow 3:moo 4:spam 4:eggs e |
{ "cow":"moo", "spam":"eggs" } |
*리스트와 딕셔너리에 시작에 l과 d로 구분하고 e로 마지막임을 표시한부분을 잘 보자*
실제 Tracker응답을 보자
|
d 8:interval i1800e
5:peers 12: ... e |
*d로 시작하니 딕셔너리임을 알수 있다
*실제로는 한 줄의 바이너리 데이터로 온다
JSON 타입으로 해석하면…
|
{ "interval":1800, "peers":"..." } |
**Interval = 30분뒤에 다시 요청하라(Tracker의 과부하를 막기 위한 값)
여기서 핵심 정보가 바로 peer 정보이다(실제 Peer 목록이 들어있다)
Peer List 형식 = 2가지
방식이 있음
1.딕셔너리 방식
|
[ { "ip":"1.2.3.4", "port":6881 } ] |
2.Compact 방식
=대부분 사용하며 훨씬 크기도 작다
Compact Peer Format
=Peer 하나당 ( IP 4바이트 , Port 2바이트 = 6 바이트만 사용)
=ex) 01 02 03 04 1A E1 -> 앞 4바이트 1.2.3.4 뒤 2바이트 6881
è 01 02 03 04 1A E1 가 1.2.3.4:6881 가 된다
여러 Peer가 있을때 상황을 보면
|
01 02 03 04 1A
E1 05 06 07 08 1A
E1 09 0A 0B 0C 1A
E1 |
1.2.3.4:6881 5.6.7.8:6881 9.10.11.12:6881 |
으로 6 바이트씩 끊어서 읽으면 된다
Step – 4
== Tracker 통신 분석
패킷의 관점에서 살펴보면 다음과 같이 Tracer에게 질의한다
è Client---------(infoHash, Peer_id, port)----------> Tracker
그럼 Tracker는 다음과 같이 응답해 준다
|
interval = 1800
peers = [ 1.2.3.4:6881 5.6.7.8:51413 9.9.9.9:6881 ] |
그럼 이제 Client 는 전달받은
Peer인 1.2.3.4 에게 연결을 시도하고 실패하면 다음 5.6.7.8에 연결을 시도하며 순차적으로 진행한다
Step – 5
==다음화 예고 – Peer
HandShack 는 어떻게 이루어 질까?
l BitTorrent Handshake
l Peer ID
l Reserved Bytes
l InfoHash 검증
l C#으로 Handshake 생성하기
Tracker에게 Peer를
받았다고 끝이 아니고 이제부터 진짜 본격적입니다~
Peer와 TCP 연결이
성공하면 BitTorrent 프로토콜의 첫번째 메시지인
HandShacke가 시작 되기 때문입니다
===== 실습 =====
=C# 콘솔 프로그램으로 진행
==Compact Peer를 파싱하는 프로그램을 만들어 보자
예제 데이터
|
byte[] peers = { 1, 2, 3, 4, 0x1A, 0xE1, 5, 6, 7, 8, 0x1A, 0xE1, 9, 10, 11, 12, 0xC8, 0xD5 }; |
파싱 코드
|
using System;
namespace
TorrentTrackerDemo { class Program { static void Main(string[] args) { // Tracker가 보내준 Peer 데이터라고 가정 byte[] peers = { // 1.2.3.4:6881 1, 2, 3, 4, 0x1A, 0xE1,
// 5.6.7.8:6881 5, 6, 7, 8, 0x1A, 0xE1,
// 9.10.11.12:51413 9, 10, 11, 12, 0xC8, 0xD5 };
Console.WriteLine("=== Peer
List ==="); Console.WriteLine();
for (int i = 0; i <
peers.Length; i += 6) { string ip = $"{peers[i]}."
+ $"{peers[i +
1]}." + $"{peers[i +
2]}." + $"{peers[i +
3]}";
ushort port = (ushort)((peers[i + 4]
<< 8) | peers[i + 5]);
Console.WriteLine($"{ip}:{port}"); }
Console.WriteLine(); Console.WriteLine("Press any
key..."); Console.ReadKey(); } } } |
=변환이 잘 됫네요~
***당부의 말***
만들려고 하는 Torrent Tracker 프로젝트 목표는 이거에요
è 어떤 토렌트가, 어떤 Peer에
의해 , 어디서 공유되고 있는지 관찰한다
그 첫번째가 바로 Tracker 응답 분석이에요! 그래서 Tracker를 읽을수 있으면
l 현재
참여 Peer 수
l Peer IP
l Peer Port
l 토렌트
활성도
를 수집할수 있답니다! 그래서 지금까지 두 번의 실습이 문자열 파싱이나
바이트 데이터 해석 정도라서 "이게 뭐가 중요한 거지?"
라고 생각하실 수도 있습니다…
하지만 실제 네트워크 프로그래밍에서는 데이터를 주고받는 것보다도, 받은
데이터를 정확하게 해석하는 과정이 훨씬 중요할 때가 많습니다…
지금까지 만든 기능들은 모두 최종 목표인 Torrent Tracker를
구성하는 부품들입니다..
댓글 없음:
댓글 쓰기