Namun P2P Messenger lain
Membaca ulasan dan dokumentasi bahasa tidak cukup untuk mempelajari cara menulis aplikasi yang kurang lebih bermanfaat di dalamnya.
Pastikan untuk melakukan konsolidasi, Anda perlu membuat sesuatu yang menarik agar perkembangannya dapat digunakan dalam tugas-tugas lain.

Artikel ini ditujukan untuk pemula yang tertarik dengan jaringan go and peer-to-peer.
Dan untuk para profesional yang dapat menawarkan ide-ide yang masuk akal atau mengkritik secara konstruktif.
Saya telah pemrograman untuk beberapa waktu dengan berbagai tingkat pencelupan di java, php, js, python.
Dan setiap bahasa pemrograman bagus di bidangnya.
Area utama untuk Go adalah penciptaan layanan terdistribusi, layanan microser.
Paling sering, layanan mikro adalah program kecil yang melakukan fungsi yang sangat terspesialisasi.
Tetapi layanan microser masih harus dapat berkomunikasi satu sama lain, sehingga alat untuk membuat layanan microser harus memungkinkan jaringan yang mudah dan tidak menyakitkan.
Untuk menguji ini, kita akan menulis sebuah aplikasi yang mengatur jaringan teman sebaya yang terdesentralisasi (Peer-To-Peer), yang paling sederhana adalah p2p messenger (omong-omong, apakah ada sinonim Rusia untuk kata ini?).
Dalam kode tersebut, saya secara aktif menciptakan sepeda dan menginjak menyapu untuk merasakan golang, mendapatkan kritik konstruktif dan saran rasional.
Apa yang kita lakukan
Peer (peer) - contoh unik dari messenger.
Utusan kami harus dapat:
- Temukan pesta terdekat
- Menjalin koneksi dengan rekan-rekan lain
- Enkripsi pertukaran data dengan teman sebaya
- Terima pesan dari pengguna
- Tampilkan pesan ke pengguna
Untuk membuat tugas sedikit lebih menarik, mari kita buat semuanya melalui satu port jaringan.

Jika Anda menarik port ini melalui HTTP, kami mendapatkan aplikasi Bereaksi yang menarik port yang sama dengan membuat koneksi socket web.
Jika Anda menarik port melalui HTTP bukan dari mesin lokal, maka kami menunjukkan spanduk.
Jika peer lain terhubung ke port ini, maka koneksi permanen dibuat dengan enkripsi ujung ke ujung.
Tentukan jenis koneksi yang masuk
Pertama, buka port untuk mendengarkan dan kami akan menunggu koneksi baru.
net.ListenTCP("tcp", tcpAddr)
Pada koneksi baru, baca 4 byte pertama.
Kami mengambil daftar kata kerja HTTP dan membandingkan 4 byte kami dengannya.
Sekarang kami menentukan apakah koneksi dibuat dari mesin lokal, dan jika tidak, kami merespons dengan spanduk dan menutup telepon.
buf, err := readWriter.Peek(4) if ItIsHttp(buf) { handleHttp(readWriter, conn, p) } else { peer := proto.NewPeer(conn) p.HandleProto(readWriter, peer) } if !strings.EqualFold(s, "127") && !strings.EqualFold(s, "[::") { response.Body = ioutil.NopCloser(strings.NewReader("Peer To Peer Messenger. see https://github.com/easmith/p2p-messenger")) }
Jika koneksi bersifat lokal, maka kami merespons dengan file yang sesuai dengan permintaan.
Kemudian saya memutuskan untuk menulis sendiri prosesnya, walaupun saya bisa menggunakan handler yang tersedia di perpustakaan standar.
Jika jalur diminta, maka kami mencoba membuat koneksi websocket.
Karena saya mengumpulkan sepeda dalam memproses permintaan file, saya akan melakukan pemrosesan koneksi ws menggunakan perpustakaan gorilla / websocket .
Untuk melakukan ini, buat MyWriter
dan terapkan metode di dalamnya untuk berhubungan dengan antarmuka http.ResponseWriter
dan http.Hijacker
.
Deteksi Sebaya
Untuk mencari rekan di jaringan lokal, kami akan menggunakan UDP multicast.
Kami akan mengirimkan paket dengan informasi tentang diri kami ke alamat IP Multicast.
func startMeow(address string, p *proto.Proto) { conn, err := net.DialUDP("udp", nil, addr) for { _, err := conn.Write([]byte(fmt.Sprintf("meow:%v:%v", hex.EncodeToString(p.PubKey), p.Port))) time.Sleep(1 * time.Second) } }
Dan dengarkan secara terpisah dari Multicast IP untuk semua paket UDP.
func listenMeow(address string, p *proto.Proto, handler func(p *proto.Proto, peerAddress string)) { conn, err := net.ListenMulticastUDP("udp", nil, addr) _, src, err := conn.ReadFromUDP(buffer)
Dengan demikian, kita mendeklarasikan diri kita sendiri dan belajar tentang penampilan pesta-pesta lainnya.
Mungkin untuk mengatur ini di tingkat IP, dan bahkan dalam dokumentasi resmi paket IPv4, hanya paket data multicast yang diberikan sebagai contoh kode.
Protokol Interaksi Teman
Kami akan mengemas semua komunikasi antar rekan dalam amplop (Amplop).
Pada setiap amplop selalu ada pengirim dan penerima, untuk ini kami akan menambahkan perintah (yang ia bawa bersamanya), pengidentifikasi (sejauh ini adalah nomor acak, tetapi dapat dilakukan sebagai hash konten), panjang isi dan isi amplop itu sendiri - pesan atau parameter perintah.

Perintah, (atau jenis konten) berhasil ditempatkan di bagian paling awal amplop dan kami menetapkan daftar perintah 4 byte yang tidak bersinggungan dengan nama-nama kata kerja HTTP.
Seluruh amplop selama transmisi serial ke dalam array byte.
Jabat tangan
Ketika koneksi dibuat, pesta segera meraih jabat tangan, memberikan namanya, kunci publik dan kunci publik sesaat untuk menghasilkan kunci sesi bersama.
Sebagai tanggapan, rekan menerima kumpulan data yang serupa, mendaftarkan rekan yang ditemukan dalam daftar dan menghitung (CalcSharedSecret) kunci sesi umum.
func handShake(p *proto.Proto, conn net.Conn) *proto.Peer { peer := proto.NewPeer(conn) p.SendName(peer) envelope, err := proto.ReadEnvelope(bufio.NewReader(conn)) }
Pertukaran pesta
Setelah jabat tangan, rekan-rekan bertukar daftar rekan mereka =)
Untuk melakukan ini, sebuah amplop dengan perintah LIST dikirim, dan daftar teman sebaya JSON ditempatkan di isinya.
Sebagai tanggapan, kami mendapatkan amplop yang serupa.
Kami menemukan dalam daftar yang baru dan dengan masing-masing kami mencoba untuk terhubung, berjabat tangan, bertukar pesta dan seterusnya ...
Olahpesan pengguna
Pesan khusus adalah nilai terbesar bagi kami, jadi kami akan mengenkripsi dan menandatangani setiap koneksi.
Tentang enkripsi
Dalam pustaka golang (google) standar dari paket crypto, banyak algoritma yang berbeda diimplementasikan (tidak ada standar GOST).
Yang paling nyaman untuk tanda tangan saya pikir adalah kurva Ed25519. Kami akan menggunakan perpustakaan ed25519 untuk menandatangani pesan.
Pada awalnya, saya berpikir tentang menggunakan pasangan kunci yang diperoleh dari ed25519 tidak hanya untuk penandatanganan, tetapi juga untuk menghasilkan kunci sesi.
Namun, kunci untuk penandatanganan tidak berlaku untuk menghitung kunci bersama - Anda masih perlu menyulapnya:
func CreateKeyExchangePair() (publicKey [32]byte, privateKey [32]byte) { pub, priv, err := ed25519.GenerateKey(nil) copy(publicKey[:], pub[:]) copy(privateKey[:], priv[:]) curve25519.ScalarBaseMult(&publicKey, &privateKey) }
Oleh karena itu, diputuskan untuk menghasilkan kunci sementara, dan secara umum, ini adalah pendekatan yang tepat yang tidak memberikan kesempatan bagi penyerang untuk mengambil kunci bersama.
Untuk pecinta matematika, berikut adalah tautan wiki:
Protokol Diffie - Hellman_ pada Kurva Elips
Tanda Tangan Digital EdDSA
Pembuatan kunci bersama cukup standar: pertama, untuk koneksi baru, kami menghasilkan kunci sementara, kami mengirim amplop dengan kunci publik ke soket.
Sisi yang berlawanan melakukan hal yang sama, tetapi dalam urutan yang berbeda: ia menerima amplop dengan kunci publik, menghasilkan pasangannya sendiri dan mengirimkan kunci publik ke soket.
Sekarang setiap peserta memiliki kunci singkat publik dan pribadi orang lain.
Mengalikannya, kita mendapatkan kunci yang sama untuk keduanya, yang akan kita gunakan untuk mengenkripsi pesan.
Kami akan mengenkripsi pesan dengan algoritma AES yang telah lama ada dalam mode kopling blok (CBC).
Semua implementasi ini mudah ditemukan dalam dokumentasi golang.
Satu-satunya perbaikan adalah pengisian otomatis pesan dengan nol byte untuk banyaknya panjangnya hingga panjang blok enkripsi (16 byte).
Kembali pada tahun 2013, ia menerapkan AES (dengan mode yang mirip dengan CBC) untuk mengenkripsi pesan di Telegram sebagai bagian dari kontes dari Pavel Durov.
Pada saat itu, protokol Diffie-Hellman yang paling umum digunakan dalam telegram untuk menghasilkan kunci fana.
Dan untuk mengecualikan beban dari koneksi palsu, sebelum setiap pertukaran kunci, klien memecahkan masalah faktorisasi.
GUI
Kita perlu menunjukkan daftar teman dan daftar pesan dengannya, dan juga menanggapi pesan baru dengan menambah penghitung di sebelah nama rekan.
Di sini tanpa masalah - ReactJS + websocket.
Pesan soket web pada dasarnya adalah amplop unik, hanya saja tidak mengandung cipherteks.
Semua dari mereka adalah "ahli waris" dari tipe WsCmd
dan diserialisasi dalam JSON pada saat transfer.
Jadi, permintaan HTTP datang ke root ("/"), sekarang untuk menampilkan bagian depan, lihat di direktori "front / build" dan berikan index.html
Nah antarmuka dibuat, sekarang pilihan untuk pengguna adalah: jalankan di browser atau di jendela yang terpisah - WebView.
Untuk opsi terakhir digunakan zserge / webview
e := webview.Open("Peer To Peer Messenger", fmt.Sprintf("http://localhost:%v", initParams.Port), 800, 600, false)
Untuk membangun aplikasi dengannya, Anda perlu menginstal sistem lain
sudo apt install libwebkit2gtk-4.0-dev
Dalam proses berpikir tentang GUI, saya menemukan banyak perpustakaan untuk GTK, QT, dan antarmuka konsol akan terlihat sangat culun - https://github.com/jroimartin/gocui - menurut saya ide yang sangat menarik.
Peluncuran Messenger
Instalasi golang
Tentu saja, Anda harus menginstal go terlebih dahulu.
Untuk melakukan ini, saya sangat merekomendasikan menggunakan instruksi golang.org/doc/install .
Instruksi sederhana untuk bash script
Unduh aplikasi di GOPATH
Sudah diatur sedemikian rupa sehingga semua perpustakaan dan bahkan proyek Anda harus dalam apa yang disebut GOPATH.
Secara default, ini adalah $ HOME / go. Go memungkinkan Anda untuk menarik sumber dari repositori publik dengan perintah sederhana:
go get github.com/easmith/p2p-messenger
Sekarang, di $HOME/go/src/github.com/easmith/p2p-messenger
sumber dari cabang master akan muncul
Instalasi NPM dan perakitan depan
Seperti yang saya tulis di atas, GUI kami adalah aplikasi web dengan front di ReactJs, jadi front masih perlu dirakit.
Nodejs + npm - di sini seperti biasa.
Untuk jaga-jaga, berikut adalah instruksi untuk ubuntu
Sekarang kita mulai perakitan depan sebagai standar
cd front npm update npm run build
Bagian depan siap!
Luncurkan
Mari kita kembali ke root dan meluncurkan pesta utusan kita.
Saat memulai, kita dapat menentukan nama rekan, port, file dengan alamat rekan-rekan lain dan bendera yang menunjukkan apakah akan meluncurkan WebView.
Secara default, $USER@$HOSTNAME
digunakan sebagai nama $USER@$HOSTNAME
dan port 35035.
Jadi, kami memulai dan mengobrol dengan teman-teman di jaringan lokal.
go run app.go -name Snowden
Umpan balik tentang pemrograman golang
Apa selanjutnya
Jadi messenger Peer-To-Peer yang paling sederhana diterapkan.
Kerucut dijejalkan, lebih jauh Anda dapat meningkatkan fungsionalitas pengguna: mengirim file, gambar, audio, emotikon, dll., Dll.
Dan Anda tidak dapat menemukan protokol Anda, dan menggunakan Bufer Protokol Google,
Hubungkan blockchain dan lindungi diri Anda dari spam menggunakan kontrak pintar Ethereum.
Pada kontrak pintar, atur obrolan grup, saluran, sistem nama, avatar, dan profil pengguna.
Sangat penting untuk menjalankan seed peer, mengimplementasikan bypass NAT, dan mengirim pesan dari peer to peer.
Akibatnya, Anda mendapatkan telegram / telepon pengganti yang baik, Anda hanya perlu mentransfer semua teman Anda di sana =)
Kegunaan
Beberapa tautanDalam proses pengerjaan messenger, saya menemukan halaman yang menarik untuk pengembang pemula.
Saya membaginya dengan Anda:
golang.org/doc/ - dokumentasi bahasa, semuanya sederhana, jelas dan dengan contoh. Dokumentasi yang sama dapat dijalankan secara lokal dengan perintah
godoc -HTTP=:6060
gobyexample.com - kumpulan contoh sederhana
golang-book.ru - buku bagus dalam bahasa Rusia
github.com/dariubs/GoBooks adalah kumpulan buku tentang Go.
awesome-go.com - Daftar pustaka, kerangka kerja dan aplikasi menarik saat bepergian. Kategorisasi lebih atau kurang, tetapi deskripsi banyak dari mereka sangat langka, yang tidak membantu pencarian dengan Ctrl + F