ไคลเอนต์ BitTorrent ที่ลงมือสร้างขึ้นเองตั้งแต่ต้น
(github.com/piyushgupta53)- โปรเจ็กต์โอเพนซอร์สนี้คือ ไคลเอนต์ BitTorrent ที่พัฒนาด้วยภาษา Go โดยลงมือสร้างลอจิกพื้นฐานสำหรับการดาวน์โหลดไฟล์ขึ้นมาเอง
- จัดการ การเข้ารหัส/ถอดรหัส Bencode ด้วยตัวเอง และมีความสามารถด้านการตรวจสอบข้อผิดพลาดที่แข็งแกร่ง
- รองรับฟังก์ชันหลักอย่างครบถ้วน เช่น การแยกวิเคราะห์ไฟล์ .torrent, การคำนวณ info hash, การสื่อสารระหว่างเพียร์
- มีฟีเจอร์ที่ช่วยให้ใช้งานได้จริงมากขึ้น เช่น การดาวน์โหลดพร้อมกัน การประกอบไฟล์ และการจัดการพื้นที่เก็บข้อมูลระดับบล็อก
- เมื่อเทียบกับโอเพนซอร์ส BitTorrent ที่มีอยู่เดิม โปรเจ็กต์นี้มีจุดเด่นด้าน ความเรียบง่ายของภาษา Go, โครงสร้างโค้ดที่ชัดเจน และความเป็นโมดูล
ภาพรวม
โปรเจ็กต์นี้เป็นการสร้างไคลเอนต์ BitTorrent ขึ้นมาเองด้วยภาษา Go
ให้ความสามารถในการดาวน์โหลดไฟล์ผ่านโปรโตคอล BitTorrent ในลักษณะพัฒนาขึ้นเอง
โดยมุ่งเน้นที่ฟังก์ชันหลักอย่าง การแยกวิเคราะห์ไฟล์ทอร์เรนต์, การค้นหาเพียร์, การดาวน์โหลดไฟล์
ฟีเจอร์หลัก
-
การเข้ารหัส/ถอดรหัส Bencode
- รองรับ Bencode ทุกประเภท เช่น สตริง จำนวนเต็ม ลิสต์ และดิกชันนารี
- ใช้การจัดการข้อผิดพลาดและการตรวจสอบข้อมูลอย่างเข้มงวด
-
การจัดการไฟล์ทอร์เรนต์
- แยกวิเคราะห์ได้ทั้งทอร์เรนต์ไฟล์เดี่ยวและหลายไฟล์
- ดึง info hash และแฮชของแต่ละชิ้นส่วนได้ พร้อมรองรับทุกฟิลด์มาตรฐาน
-
การค้นหาและสื่อสารกับเพียร์
- รองรับ HTTP tracker
- พัฒนาโปรโตคอลแฮนด์เชกระหว่างเพียร์
- รองรับโปรโตคอลข้อความของ BitTorrent และการจัดการการเชื่อมต่อเพียร์
-
ความสามารถด้านการดาวน์โหลด
- จัดการในระดับชิ้นส่วนและบล็อก
- รองรับการดาวน์โหลดพร้อมกัน
- ติดตามความคืบหน้าการดาวน์โหลดและประกอบไฟล์
- เพิ่มประสิทธิภาพด้วยการจัดการสตอเรจระดับบล็อก
โครงสร้างโปรเจ็กต์
- cmd/ : อินเทอร์เฟซบรรทัดคำสั่งและไฟล์สำหรับรัน
- internal/
- bencode/ : ฟังก์ชันเข้ารหัสและถอดรหัส Bencode
- torrent/ : การแยกวิเคราะห์และจัดการไฟล์ทอร์เรนต์
- tracker/ : การพัฒนาโปรโตคอล tracker
- peer/ : ฟังก์ชันการสื่อสารระหว่างเพียร์
- download/ : ฟังก์ชันจัดการการดาวน์โหลด
- pkg/ : ชุดแพ็กเกจที่สามารถเปิดเผยให้ภายนอกใช้งานได้
ข้อกำหนด
- ต้องใช้ Go 1.21 ขึ้นไป
วิธีใช้งาน
- ขณะนี้โปรเจ็กต์ยังอยู่ในช่วงเริ่มต้นของการพัฒนา โดยจะมีการเพิ่มคำแนะนำการใช้งานในภายหลัง
สถานะการพัฒนาและแผนงาน
- ขณะนี้กำลังพัฒนาอย่างต่อเนื่อง
- รายละเอียดของขั้นตอนการพัฒนาถูกบันทึกไว้ในไฟล์ checkpoint.md
- แผนในอนาคต:
- รองรับ Magnet link
- โปรโตคอลแลกเปลี่ยนเมทาดาทา
- มีแผนรองรับ DHT (Distributed Hash Table)
เอกสารอ้างอิง
- ข้อกำหนดโปรโตคอล BitTorrent
- ข้อกำหนด Bencode
ความสำคัญและจุดเด่นของโปรเจ็กต์
- โปรเจ็กต์นี้ใช้ประโยชน์จาก ไวยากรณ์ที่เรียบง่ายและการทำงานแบบขนานของภาษา Go เพื่อสร้างส่วนที่ซับซ้อนของไคลเอนต์ BitTorrent ให้เป็น โมดูลที่ชัดเจน
- โครงสร้างที่ชัดเจนและขยายต่อได้ง่าย รวมถึงดูแลรักษาได้สะดวก ทำให้มีข้อดีทั้งในแง่การเรียนรู้และการนำไปใช้จริง
- แม้จะยังอยู่ใน ระยะเริ่มต้น แต่ก็สามารถทำฟังก์ชันหลักของโปรโตคอล BitTorrent ได้อย่างรวดเร็ว
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
มีข้อเสนอแนะว่าควรกำหนดเพดานขนาดของการจัดสรรหน่วยความจำแบบไดนามิกในตัวถอดรหัส bencode เพราะค่าที่รับเข้ามาจากไฟล์ทอร์เรนต์หรือจาก announce ไม่น่าเชื่อถือ และอินพุตที่เป็นอันตรายอาจขอจัดสรรหน่วยความจำขนาดใหญ่มากจนทำให้เกิดการปฏิเสธการให้บริการ (DoS) ได้ สำหรับการแยกวิเคราะห์สตริง สามารถตั้งขีดจำกัดที่เหมาะสมเป็นความยาวอินพุตที่เหลืออยู่ได้ เพราะทอร์เรนต์ที่ถูกต้องไม่ควรมีสตริงที่ยาวเกินกว่าความยาวไฟล์ที่เหลือ
โปรเจ็กต์ดูสะอาดและเรียบง่ายดีมาก น่าจะดีถ้าเพิ่มตัวอย่างการใช้งานแบบบรรทัดเดียวใน Readme เช่น เพิ่มประโยคที่แสดงวิธีใช้ประมาณ
./go-torrent My-Linux-Distro-Wink-ISO.torrentและถ้าเพิ่มความสามารถtorrent.ParseFromUrlได้ด้วยก็จะยิ่งดี ทุกคนน่าจะคุ้มค่าที่จะลองประสบการณ์แบบนี้สักครั้งใน “การเดินทางทางจิตวิญญาณ” ของตัวเองแนะนำชาเลนจ์ที่คล้ายกันจาก codecrafters โดยในคอร์สนี้จะมีการช่วยเรื่องความคืบหน้าของโปรเซสและการทดสอบต่าง ๆ เคยลองใช้ฟรีหนึ่งเดือนแล้วค่อนข้างสนุก
https://app.codecrafters.io/courses/bittorrent/overview
ในฐานะคนที่ไม่ใช่นักพัฒนา Go สงสัยว่าทำไมถึงใช้ Go 1.21 เวอร์ชันเก่า มีเหตุผลพิเศษอะไรที่ยึดติดกับเวอร์ชันเก่าหรือไม่ พอค้นดูก็พบว่าหยุดการสนับสนุนไปแล้วตั้งแต่ 10 เดือนก่อน
เพราะต้องการรองรับ Windows 7 โปรเจ็กต์ที่เขียนด้วย Go 1.21.4 หรือต่ำกว่ายังทำงานได้บน Windows เกือบทุกเครื่องตั้งแต่ปี 2009 เป็นต้นมา แต่ถ้าใช้ 1.21.5 ขึ้นไป จะทำงานได้แค่บนเครื่องรุ่นใหม่และ Windows 10, 11 เท่านั้น โดยแทบไม่มีข้อดีเป็นพิเศษ
https://github.com/golang/go/issues/64622
README น่าจะเขียนโดย AI เพราะในไฟล์ go.mod จริงระบุ Go เวอร์ชันเป็น 1.23.1 ดังนั้นสุดท้ายแล้วจึงต้องใช้ 1.23.1 ขึ้นไป
https://github.com/piyushgupta53/go-torrent-client/blob/6130f4e/go.mod#L3 https://go.dev/doc/modules/gomod-ref#go-notes
เป็นโปรเจ็กต์ที่เจ๋งมาก ตอนเรียนมหาวิทยาลัยเคยทำสิ่งนี้เป็นโปรเจ็กต์จบในวิชาเน็ตเวิร์กของ Georgia Tech ถึงแม้โค้ดจะหายไปแล้ว แต่บทเรียนที่ได้ยังติดตัวไปตลอด โปรเจ็กต์แบบนี้เป็นวิธีที่ดีมากในการเรียนรู้ภาษาใหม่
มีคนถามว่ารองรับ magnet link หรือยัง
แก้ไข: ทราบแล้วว่าเป็นฟีเจอร์ที่จะเพิ่มในอนาคต
มีคนสงสัยว่าสร้างสิ่งนี้ขึ้นมาได้อย่างไร ดูสเปกของโปรโตคอลโดยตรงหรืออ้างอิงจาก implementation อื่น ๆ หรือเปล่า เพราะสงสัยมาตลอดว่าการทำสิ่งแบบนี้จากศูนย์เริ่มต้นกันอย่างไร
https://www.bittorrent.org/beps/bep_0003.html
ส่วนส่วนขยายเพิ่มเติมอยู่ที่
https://www.bittorrent.org/beps/bep_0000.html
สิ่งสำคัญคือแบ่งงานออกเป็นชิ้นเล็ก ๆ มากพอที่จะตรวจสอบผลลัพธ์ได้เอง ตัวอย่างเช่นผมเริ่มจากการ parse ไฟล์
.torrentซึ่งต้องลงมือทำ bencoding เอง พอลองดาวน์โหลด.torrentของ Arch Linux มาก็พบว่าฟอร์แมตไม่ถูกต้อง และมีคีย์ที่ไม่คาดคิดอย่างurl-listโผล่มา พอไปค้นดูก็พบว่าเกี่ยวข้องกับ bep_0019 สุดท้ายก็ parse ไฟล์.torrentของ Debian Linux ได้สำเร็จหลังจากนั้นก็ทำทั้งคำขอ announce แบบ HTTP ไปยัง tracker และ peer protocol ต่อ โดย peer protocol ค่อนข้างยาก และท่าทีแบบทดลองไปเรื่อย ๆ ช่วยได้มาก ผมลบ announce URL ออกจากทอร์เรนต์ Debian เพื่อให้ไม่มี peers เลย จากนั้นเพิ่มไคลเอนต์ของตัวเองเข้าไปใน KTorrent โดยตรงเพื่อสังเกตข้อความที่ส่งไปมาระหว่างกัน แล้วค่อยปรับโค้ดของตัวเองตามสิ่งที่เห็น มีการลองผิดลองถูกและดีบักอยู่มาก
รายละเอียดบางอย่างของโปรโตคอลหาไม่เจอจริง ๆ ในเอกสารทางการ เลยมีบางครั้งที่ต้องถาม ChatGPT เล็ก ๆ น้อย ๆ และแต่ละไคลเอนต์ก็มี implementation ต่างกันเล็กน้อย ทำให้อัลกอริทึมเชิงลึกหลายอย่างไม่ชัดเจน เช่น จะเลือกบล็อกไหนมารับ จะเชื่อมต่อกับ peer ไหน และ choke/unchoke ทำงานอย่างไร สิ่งเหล่านี้ไม่มีการสรุปไว้อย่างดี การค้นหาบนเว็บช่วยได้มาก
นอกจากนี้เว็บไซต์ https://wiki.theory.org/Main_Page ก็มีข้อมูลที่เป็นประโยชน์
ตอนนี้ไปถึงขั้นที่ดาวน์โหลด/อัปโหลดกับ KTorrent ได้ครบแล้ว ขั้นต่อไปคือทำอัลกอริทึมสำหรับดึง peer จาก tracker เลือกบล็อกที่จะดาวน์โหลด และบันทึกลงไฟล์
ถ้าอยากรู้กระบวนการละเอียดกว่านี้ก็ถามมาได้เสมอ
มีคนถามว่าการเพิ่ม GUI จะยากแค่ไหน เพราะไม่ค่อยเคยเห็นตัวอย่างการทำ GUI ด้วย Go มากนัก
ส่วนตัวชอบ https://github.com/AllenDang/giu ซึ่งเป็น wrapper ของ ImGui
ตัวที่ฟีเจอร์เยอะที่สุดน่าจะเป็น unison แต่ไม่แน่ใจว่าใช้งานจริงแพร่หลายแค่ไหน และน่าจะมีเอกสารค่อนข้างน้อย https://github.com/richardwilkes/unison
Gio เป็นเฟรมเวิร์ก GUI แนวใหม่ และถูกใช้ใน Tailscale กับ gotraceui https://gioui.org
Wails เรียนรู้ง่ายถ้ามีประสบการณ์พัฒนาเว็บ https://wails.io
binding ของ GTK4 ก็ดูน่าสนใจ https://github.com/diamondburned/gotk4
Cogent Core ก็ดูน่าสนุก แต่ผมลองแค่ช่วงสั้น ๆ ก่อนจะย้ายไปใช้ภาษา Odin แทน Go https://www.cogentcore.org/core
ส่วน Fyne นั้นโดยส่วนตัวเจอปัญหาเรื่องประสิทธิภาพค่อนข้างมากในหลายเครื่องและหลายระบบปฏิบัติการ แต่ก็ยังเป็นเฟรมเวิร์ก GUI ที่ดังที่สุดอยู่ดี https://fyne.io
มีคนบอกว่าสนใจโปรเจ็กต์แบบนี้เลยเคยคิดว่าจะลองทำดู อยากรู้ว่ามันยากแค่ไหน และคิดว่าตอนนี้พัฒนาไปสมบูรณ์แค่ไหนแล้ว รวมถึงได้ทำฟีเจอร์ซับซ้อนอย่าง DHT, Magnet, NAT traversal หรือยัง และยังไม่แน่ใจด้วยซ้ำว่าถ้าต้องการรองรับทอร์เรนต์เกือบทั้งหมดที่มีอยู่จริง จะต้องมีรายการฟีเจอร์จำเป็นอะไรบ้าง เพราะโปรโตคอลเกี่ยวกับทอร์เรนต์มีเยอะมาก จนไม่รู้แม้แต่รายการทั้งหมดหรือแต่ละโปรโตคอลมีไว้ทำอะไร
ระดับความยากแตกต่างกันมากตามประสบการณ์ ความชำนาญในภาษา และทัศนคติแบบชอบทดลอง ตัวอย่างเช่นผมเองเพิ่งเริ่มทำ Bittorrent client ด้วย Go เมื่อสัปดาห์ก่อน แต่ในเวลาแค่สัปดาห์เดียวก็มาถึงประมาณ 80% ของโปรเจ็กต์ที่โพสต์ที่นี่แล้ว เพราะมีพื้นฐาน Go โปรโตคอล และเน็ตเวิร์กมากพอ และคุ้นเคยกับการลองของใหม่อยู่เสมอ
สเปกทางการของ Bittorrent เองสั้นมาก ใช้เวลาอ่านและทำความเข้าใจประมาณชั่วโมงเดียว https://www.bittorrent.org/beps/bep_0003.html
แต่โปรโตคอลส่วนขยายรอบข้างมีจำนวนมาก และแต่ละไคลเอนต์ก็รองรับไม่เท่ากัน ตัวอย่างเช่นหลายตัวจะลองใช้ protocol encryption ก่อน (ซึ่งจริง ๆ เป็นการทำให้อ่านยากมากกว่าการเข้ารหัส) แล้วถ้าไม่ได้ค่อยกลับไปใช้โปรโตคอลปกติ
ถ้าคุณแค่อยากดาวน์โหลดจากไฟล์
.torrentทางการ เช่นดิสโทร Linux ความยากจะลดลงชัดเจน เพราะมักเป็นไฟล์เดียว มี tracker และ peers ส่วนใหญ่ใช้โปรโตคอลมาตรฐาน จึงทำงานได้แม้อยู่หลัง NAT โดยไม่ต้องเปิดพอร์ตฝั่งในแน่นอนว่าถ้าต้องการรองรับทอร์เรนต์ทั่วไปจริง ๆ โดยเฉพาะสายสีเทา ก็ต้องค่อย ๆ เพิ่มความสามารถอย่างการ parse magnet link, การหา peer ผ่าน DHT และ UPnP สำหรับ map พอร์ตอัตโนมัติ แต่ทั้งหมดนี้ก็ยังสามารถแบ่งทำทีละฟีเจอร์ได้ ยิ่งมีฟีเจอร์มาก ก็ยิ่งหา peer ได้มากและแลกเปลี่ยนข้อมูลได้สำเร็จมากขึ้น
ค่อนข้างท้าทายทีเดียว ต้องเรียนรู้ทั้งโปรโตคอล วิธีการ bencoding และวางภาพรวมของโครงสร้างทั้งหมดในหัวก่อนลงมือเขียนโค้ด ใช้เวลาเกือบหนึ่งเดือน Magnet กับ DHT ยังไม่รองรับ
มีคนถามว่าได้ทำ v2 และ mutable torrents หรือยัง พร้อมบอกว่าอยากให้รองรับ mutable torrents มาก ๆ