Olen nüüdseks neli kuud tegelenud projektiga "Andmekaitse- ja haldustööriistade arendamine valitsus- ja tööstussektoris, mis põhinevad plokiahelal."
Nüüd tahaksin teile rääkida, kuidas ma selle projektiga alustasin, ja nüüd kirjeldan üksikasjalikult programmi koodi.
See on esimene artikkel artiklite sarjas. Siin kirjeldan serverit ja protokolli. Tegelikult saab lugeja nendest plokiahela elementidest isegi oma versioonid kirjutada.
Eelmisel aastal tuli neil Digital Breakthrough häkatonil idee teha hajutatud pearaamatutehnoloogia abil tööstusele ja digimajandusele kasulik süsteem, arenduseks anti välja ka Innovatsiooniabi fond (peaksin kirjutama eraldi artikkel toetuse kohta neile, kes alles alustavad idufirmasid ) ja nüüd järjekorras.
Arendus toimub Go keeles ja andmebaas, kuhu plokid salvestatakse, on LevelDB.
Peamised osad on protokoll, server (mis jookseb TCP-d ja WebSocketit – esimene plokiahela sünkroonimiseks, teine klientide ühendamiseks, tehingute ja käskude saatmiseks näiteks JavaScriptist.
Nagu öeldud, on seda plokiahelat vaja eelkõige tarnijate ja klientide või mõlema ühes isikus kaubavahetuse automatiseerimiseks ja kaitsmiseks. Need inimesed ei kiirusta üksteist usaldama. Kuid ülesandeks pole mitte ainult sisseehitatud kalkulaatoriga "tšekiraamatu" loomine, vaid süsteem, mis automatiseerib enamiku toote elutsükliga töötamisel tekkivatest rutiinsetest ülesannetest. Selle asja eest vastutav baitkood, nagu plokiahelate puhul tavaks, salvestatakse tehingute sisenditesse ja väljunditesse (tehingud ise salvestatakse plokkidesse, LevelDB plokid on eelkodeeritud GOB-vormingus). Kõigepealt räägime protokollist ja serverist (aka node).
Protokoll ei ole keeruline, selle mõte on lülituda teatud andmete, tavaliselt ploki või tehingu, laadimise režiimile vastuseks spetsiaalsele käsureale ja seda on vaja ka laoseisu vahetamiseks, et sõlm teaks, kes seda teeb. on ühendatud ja kuidas neil on asju ajada (sünkroonimisseansi jaoks ühendatud sõlme nimetatakse ka "naabersõlmedeks", kuna nende IP on teada ja nende olekuandmed salvestatakse mällu).
Go programmeerijate mõistes nimetatakse kaustu (katalooge, nagu Linux neid nimetab) pakettideks, seega kirjutavad nad iga selle kataloogi Go koodiga faili algusesse paketi kausta_nimi_kus_see_fail asub. Vastasel juhul ei saa te paketti kompilaatorile edastada. Noh, see pole saladus neile, kes seda keelt oskavad. Need on paketid:
- Võrguside (server, klient, protokoll)
- Salvestatud ja edastatavate andmete struktuurid (plokk, tehing)
- Andmebaas (plokiahel)
- Konsensus
- Virnastatud virtuaalmasin (xvm)
- Abi (krüpto, tüübid) on selleks korraks kõik.
See on hariv versioon, sellel puudub protsessidevaheline interaktsioon ja mitmed eksperimentaalsed komponendid, kuid struktuur vastab sellele, millel arendust teostatakse. Kui teil on kommentaarides midagi soovitada, siis võtan seda hea meelega edasi arendamisel arvesse. Ja nüüd selgituseks serveri ja protokoll.
Vaatame kõigepealt serverit.
Serveri alamprogramm toimib andmeserverina, mis töötab TCP-protokolli peal, kasutades protokollipaketi andmestruktuure.
Rutiin kasutab järgmisi pakette: server, protokoll, liigid. Pakendis endas tcp_server.go sisaldab andmestruktuuri Serveeri.
type Serve struct {
Port string
BufSize int
ST *types.Settings
}
See võib aktsepteerida järgmisi parameetreid:
- Võrguport, mille kaudu andmeid vahetatakse
- Serveri konfiguratsioonifail JSON-vormingus
- Silumisrežiimis töötamise märk (privaatne plokiahel)
Edusammud:
- Loeb konfiguratsiooni JSON-failist
- Silumisrežiimi lipp on kontrollitud: kui see on määratud, siis võrgu sünkroonimise ajakava ei käivitu ja plokiahelat ei laadita
- Konfiguratsiooniandmete struktuuri lähtestamine ja serveri käivitamine
server
- Teostab TCP-serveri käivitamise ja võrgu interaktsiooni vastavalt protokollile.
- Sellel on serveerimisandmestruktuur, mis koosneb pordi numbrist, puhvri suurusest ja struktuuri osutajast tüübid. Seaded
- Käivita meetod käivitab võrgu interaktsiooni (antud pordi sissetulevate ühenduste kuulamine, uue ühenduse vastuvõtmisel viiakse selle töötlemine üle privaatkäepideme meetodile uues lõimes)
- В käepide ühenduse andmed loetakse puhvrisse, teisendatakse stringi esituseks ja edastatakse protokoll.Valik
- protokoll.Valik naaseb kaasa või põhjustab tõrke. kaasa seejärel üle kantud protokoll.Tõlgendadamis naaseb intrpr - tüüpi objekt InterpreteDatavõi põhjustab valiku tulemuse töötlemisel vea
- Seejärel käivitatakse lüliti intrpr.Commands[0] mis kontrollib ühte järgmistest: tulemus, arv, viga ja seal on sektsioon vaikimisi
- Jaotises kaasa lüliti leitakse väärtuse järgi intrpr.Commands[1] mis kontrollib väärtusi puhverpikkus и versioon (igal juhul kutsutakse välja vastav funktsioon)
Funktsioonid GetVersion и Puhvri pikkus on failis srvlib.go serveripakett
GetVersion(conn net.Conn, version string)
see lihtsalt prindib konsooli ja saadab parameetris edastatud versiooni kliendile:
conn.Write([]byte("result:" + version))
.
Funktsioon
BufferLength(conn net.Conn, intrpr *protocol.InterpreteData)
laadib ploki, tehingu või muud spetsiifilised andmed järgmiselt:
- Prindib konsooli protokollis määratud andmete tüübi, mida tuleb aktsepteerida:
fmt.Println("DataType:", intrpr.Commands[2])
- Loeb väärtust intrpr.Keha numbrilisele muutujale buf_len
- Loob puhvri newbuf määratud suurus:
make([]byte, buf_len)
- Saadab ok vastuse:
conn.Write([]byte("result:ok"))
- Täidab lugemisvoo puhvri täielikult:
io.ReadFull(conn, newbuf)
.
- Prindib puhvri sisu konsooli
fmt.Println(string(newbuf))
ja loetud baitide arv
fmt.Println("Bytes length:", n)
- Saadab ok vastuse:
conn.Write([]byte("result:ok"))
Serveripaketi meetodid on konfigureeritud töötlema vastuvõetud andmeid, kasutades paketi funktsioone protokoll.
Protokoll
Protokoll on vahend, mis esindab andmeid võrguvahetuses.
Valik(string) (string, viga) teostab serveri poolt vastuvõetud andmete esmast töötlemist, võtab sisendiks vastu andmete stringi ja tagastab Tõlk:
- Sisendstring jagatakse pea ja keha abil ReqParseN2(str)
- pea jagatakse elementideks ja asetatakse käsuviiluks, kasutades ReqParseHead(head)
- В lüliti (käsud[0]) vali vastuvõetud käsk (cmd, võti, aadress või sektsioon käivitub vaikimisi)
- cmd-s on kontrollitud 2 käsku lüliti(käsud[1]) — pikkus и saada versioon.
- pikkus kontrollib sisestatud andmetüüpi käsud[2] ja salvestab selle sisse andmetüüp
- Kontrollib seda keha sisaldab stringi väärtust
len(body) < 1
- Tagastab vastuse stringi:
"result:bufferlength:" + datatype + "/" + body
- saada versioon tagastab stringi
return "result:version/auto"
Tõlk
Sisaldab InterpreteData struktuuri ja teostab tagastatud andmete sekundaarset töötlemist Valik stringid ja objektide moodustamine InterpreteData.
type InterpreteData struct {
Head string
Commands []string
Body string
IsErr bool
ErrCode int
ErrMessage string
}
Funktsioon
Interprete(str string) (*InterpreteData, error)
võtab stringi vastu kaasa ning loob ja tagastab viite objektile InterpreteData.
Edusammud:
- Samamoodi Valik pea ja keha ekstraheeritakse kasutades ReqParseN2(str)
- pea jagatakse elementideks kasutades ReqParseHead(pea)
- Objekt initsialiseeritakse InterpreteData ja sellele tagastatakse osuti:
res := &InterpreteData{
Head: head,
Commands: commands,
Body: body,
}
return res, nil
Seda objekti kasutatakse server.go pakett peamine.
klient
Kliendipakett sisaldab funktsioone TCPConnect и TCPResponseData.
Funktsioon
TCPConnect(s *types.Settings, data []byte, payload []byte)
töötab järgmiselt:
- Ühendus luuakse läbitud sätete objektis määratud ühendusega
net.Dial("tcp", s.Host + ":" + s.Port)
- Andmeparameetris edastatud andmed edastatakse:
conn.Write(data)
- Vastus loetakse
resp, n, _ := TCPResponseData(conn, s.BufSize)
ja prinditakse konsoolile
fmt.Println(string(resp[:n]))
- Kui üle antakse kasulik koormus siis annab selle edasi
conn.Write(payload)
ja loeb ka serveri vastuse, printides selle konsooli
Funktsioon
TCPResponseData(conn net.Conn, bufsiz int) ([]byte, int, error)
loob määratud suurusega puhvri, loeb seal serveri vastuse ja tagastab selle puhvri ja loetud baitide arvu ning veaobjekti.
Kliendi alamprogramm
Teenib käskude saatmiseks sõlmeserveritele, samuti lühikese statistika ja testimise hankimiseks.
Saab aktsepteerida järgmisi parameetreid: JSON-vormingus konfiguratsioonifail, stringina serverisse saadetavad andmed, kasulikku koormusse saadetava faili tee, sõlmede ajakava emuleerimise lipp, numbrilise väärtusena edastatavate andmete tüüp.
- Konfiguratsiooni hankimine
st := types.ParseConfig(*config)
- Kui emu lipp on möödas, käivitub sheduler
- Kui faili teed näitav lipp f on esitatud, laadime selle andmed sisse fdb ja sisu saadetakse serverisse
client.TCPConnect(st, []byte(CMD_BUFFER_LENGTH + ":" + strconv.Itoa(*t) + "/" + strconv.Itoa(fdblen)), fdb)
- Kui faili pole määratud, saadetakse lipu andmed lihtsalt ära -d:
client.TCPConnect(st, []byte(*data), nil)
Kõik see on lihtsustatud esitus, mis näitab protokolli struktuuri. Arenduse käigus lisatakse selle struktuuri vajalik funktsionaalsus.
Teises osas räägin plokkide ja tehingute andmestruktuuridest, 3. osas WebSocket serverist JavaScriptist ühenduse loomiseks, 4. osas vaatan sünkroonimisplaanijat, seejärel pinu masinat, mis töötleb baitkoodi sisenditest ja väljunditest, krüptograafiat ja basseinid väljundite jaoks.
Allikas: www.habr.com