once you parse .torrent file you get the following components:

  • announce (url to which you need to query to get peers, also known as tracker)
  • info hash (torrent info hash which contains stuff like what files are present and the structure etc..)

You need to get the peers who have the data you want to download, you request to announce URL with info hash and other info to send you all the peers address(ip and port).

To start talking to these peers you need to first create a TCP handshake with them, this is the protocol that talk about the structure of this protocol

You have the following fields in the protocol which are sent to peer over the TCP connection:

filedsize (in bytes)purposevalue
pstrlen1length of the protocol name19 always
pstr19name of the protocol“BitTorrent protocol” always
reserved8sometimes empty, sometimes contains DHT (Distributed Hash Table)
info_hash2020 bytes info_hash which we parsed from .torrent file[20]byte("info_hash"), info_hash: structure of the files/names of the files itself which we want to download
peer_id20identifying yourself in the network[20]byte() peer_id generated by you

you create a connection to the peer ip and port with the following info

// standard go struct for BitTorrent handshake protocol
type PeerHandshake struct {
	PstrLen  uint8       // always 19
	Pstr     string      // "BitTorrent protocol"
	Reserved [8]byte     // usually empty, sometimes contains DHT
	InfoHash [20]byte    // 20 bytes info_hash read from .torrent file
	PeerID   [20]byte    // 20 bytes peerid generated by you
}


type PeerConnection struct {
	Conn       net.TCPConn
	HandShake  *PeerHandshake
}

func HandShake(peer_id [20]byte, infoHash [20]byte) net.TCPConn {
	ph := NewHandShake(infoHash, peerId)

	address := fmt.Sprintf("%s:%d", peer.IP.String(), peer.Port)  // peer ip,port extracted from talking to tracker/announce URL

	conn, err := net.DialTimeout("tcp", address, timeout)  // creating "tcp" conn
	if err != nil {
		return nil, err
	}

	_, err = conn.Write(ph.Encode())    // URL encode and send it over to peer
	if err != nil {
		return nil, err
	}

	buf := make([]byte, 68)   // since the BitTorrent handshake protocol is exactly 68 bytes
	_, err = conn.Read(buf)
	if err != nil {
		conn.Close()
		return nil, err
	}

	decodedPH, err := DecodeHandShake(buf)  // recieved output will be of the same structure as defined in PeerHandshakeProtocol struct
	if decodedPH.InfoHash != infoHash {
		return nil, fmt.Errorf("infoHash mismatch, expected: %v, got: %v", ph.InfoHash, decodedPH.InfoHash)
	}

	return &PeerConnection{Conn: conn, HandShake: decodedPH}, nil
}

Here in the above code you can see struct: PeerConnection which has Conn which is has an active TCP connection with the peer, which you can use it to download the data wanted.