2016년 11월 8일 화요일

WebTorrent 소스 분석

https://github.com/feross/webtorrent

bittorrent-dht

  • 처음 시작시 find_node로 node들을 찾는다. lookup으로 내가 원하는 info_hash를 가지고 있는 node들을 찾는다. announce로 node들에게 내가 info_hash를 다운받고 있음을 알린다. ping으로 node가 살아있는지 확인한다. 에러가 발생하면 error를 응답한다.
  • 'KRPC Protocol'에 관련된 부분은 k-rpc 모듈에 의해 이루어진다.
  • id는 k-rpc 생성시 만들어진다.
  • _tables: info_hash를 key로 하여 찾은 node 정보를 저장한다.
  • _values: arbitrary payload를 저장한다.
  • _peers: 나에게 announce 쿼리를 보낸 peer 정보를 저장한다.
  • 5분마다 secret 값을 변경한다. secret는 token 생성에 사용된다.
  • routing table에 있는 값들의 저장을 위해 toJSON 함수를 제공한다.
    • toJSON 함수를 사용하여 뽑아낸 node와 value의 정보를 디스크등에 저장해 놓았다가 다시 시작시 addNode를 통해 routing table에 추가할 수 있다.
  • find_node
    • query: { "a": { "id": "<querying nodes id>", "target": "<id of target node>" }
    • 이 작업이 이루어짐으로서 서버로부터 관련 node들의 정보가 routing table에 저장된다.
    • k-rpc에서 기본으로 사용하는 서버들(BOOTSTRAP_NODES)이 있다: router.bittorrent.com:6881, router.utorrent.com:6881, dht.transmissionbt.com:6881
  • lookup
    • query: { "q": "get-peers", "a": { "id": "<querying nodes id>", "info_hash": "<20-byte infohash of target torrent>" } }
    • 응답이 오면 k-bucket에 넣고(id, host, port, token) 'peer' event를 emit한다. peer는 {host, port}이다.
  • announce
    • table에서 info_hash에 연결되어 있는 k-bucket을 찾는다. 여기에는 info_hash를 가지고 있는 node들의 정보가 들어있다. 여기서 info_hash에 closest인 node들을 찾아 이들에 announce를 한다.
    • query: { "q": "announce_peer", "a": { "id": "<querying nodes id>", "token": "<response to a previous get_peers query>", "info_hash": "<20-byte infohash of target torrent>", "port": "port", "implied_port": "0 or 1" } }
  • ping
    • query: { "q": "ping" }
    • response: { "r": "<querying nodes id>" }
  • error
    • response: { "e":[201, "A Generic Error Ocurred"] }

webtorrent

  • handshake를 보낸다. -> (bitfield를 받는다. -> request를 보낸다. -> piece를 받는다.) -> keep-alive를 60s마다 받는다. -> (interested를 받는다. -> unchoked를 보낸다.) -> peer가 DHT를 지원하는 경우 자신의 DHT 포트를 알리는 port를 받는다. -> 모든 piece를 다 받은 경우 본인을 seeder로 설정하고 remote peer에 choked를 보낸다.

BitTorrent Protocol

  • handshake: <pstrlen><pstr><reserved><info_hash><peer_id>
    • 상대 client와 연결시 첫번째로 보내는 메시지.
    • version 1.0의 경우 pstrlen = 19이고 pstr = "BitTorrent protocol" 이다.
  • message format: <length prefix><message ID><payload>
  • port: <len=0003><id=9><listen-port>
    • DHT를 구현하고 있는 경우 remote peer에게 보내는 메시지.
  • keep-alive: <len=0000>
    • 연결이 끊기지 않도록 하기 위해 보내는 메시지. 보통 2분마다 보낸다(webtorrent는 1분마다 보낸다).
  • bitfield: <len=0001+X><id=5><bitfield>
    • 어떤 piece를 가지고 있고 안가지고 있는지를 알리는 메시지.
    • bit에서 cleared는 missing piece를 set은 downloaded를 의미한다.
    • lazy bitfield: 모든 bit를 cleared 하여 받은 부분이 없다고 알린 후, have 메시지로 가지고 있는 부분을 알리는 방법. ISP filtering을 막는 방법이라고 알려져 있다.
  • have: <len=0005><id=4><piece index>
    • 가지고 있는 piece의 index를 알리는 메시지
  • request: <len=0013><id=6><index><begin><length>
    • 지정한 piece를 요청한다.
  • piece: <len=0009+X><id=7><index><begin><block>
    • 요청받은 piece를 응답한다.
  • state information: interested and choked
    • interested는 remote peer가 block을 요청할 것이라는 것을 의미하고 choked는 remote peer가 요청에 응답을 주지 않을 것이라는 것을 의미한다.
    • interested: <len=0001><id=2>
    • not interested: <len=0001><id=3>
    • choke: <len=0001><id=0>
    • unchoke: <len=0001><id=1>

댓글 없음:

댓글 쓰기

Building asynchronous views in SwiftUI 정리

Handling loading states within SwiftUI views self loading views View model 사용하기 Combine을 사용한 AnyPublisher Making SwiftUI views refreshable r...