1 / 27

Go networking

Go networking. Peter Borovansk ý, KAI, I-18, borovan (a)ii.fmph.uniba.sk. Prejdeme si v Go tri úrovne tzv. TCP Stacku, a naprogramujeme klient/server aplikáciu cez sockety, príklad chat sntp udp klient (time server klient) f tp server & ftp klient w ebcrawler

callie
Download Presentation

Go networking

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Go networking Peter Borovanský, KAI, I-18, borovan(a)ii.fmph.uniba.sk Prejdeme si v Go tri úrovne tzv. TCP Stacku, a naprogramujeme • klient/server aplikáciu cez sockety, príklad chat • sntp udp klient(time server klient) • ftp server & ftp klient • webcrawler • tiny wiki – malá web app Zdroje: • http://golang.org/doc/articles/wiki/ • http://jan.newmarch.name/go

  2. Client socket import("bufio""fmt""io""net")funcmain(){// vytvorenie spojenia socket-socket conn,err:=net.Dial("tcp","google.com:80") iferr!=nil{ fmt.Println("connectionerror:"+err.Error()) }else{ // písanie do conn : net.Conn fmt.Fprintf(conn,"HEAD/HTTP/1.0\r\n\r\n") r:=bufio.NewReader(conn)// bufio wrapper for{ line,_,err:=r.ReadLine()// čítanie z conn iferr==io.EOF{ break } fmt.Printf("%s\n",line) } } } net1/netclient1.go

  3. Pomocou putty

  4. RFC 4330 http://tools.ietf.org/html/rfc4330 Sntp klient conn,err:=net.Dial("udp","0.sk.pool.ntp.org:123") iferr!=nil{return} r:=bufio.NewReader(conn) w:=bufio.NewWriter(conn) data:=make([]byte,48) data[0]=3<<3|3 conn.SetDeadline(time.Now().Add(5*time.Second)) deferconn.Close() w.Write(data)//sendrequest w.Flush() data,_,err=r.ReadLine()//readresponse varsec,fracuint64 sec=uint64(data[43])|uint64(data[42])<<8|uint64(data[41])<<16|uint64(data[40])<<24 frac=uint64(data[47])|uint64(data[46])<<8|uint64(data[45])<<16|uint64(data[44])<<24 nsec:=sec*1e9 nsec+=(frac*1e9)>>32 t:=time.Date(1900,1,1,0,0,0,0,time.UTC).Add(time.Duration(nsec)).Local() fmt.Printf("Networktime:%v\n",t) sntp/sntpclient.go

  5. Jednovláknový server import("bufio""fmt""io""net") funcmain(){ // porty <1024 majú špeciálne určenie ln,err:=net.Listen("tcp",":8080")// server socket iferr!=nil{ fmt.Println("connectionerror:"+err.Error()) }else{ conn,err:=ln.Accept()// blokuje kým ja niekto iferr!=nil{// nepokúsi o spojenie fmt.Println("error:"+err.Error()) }else{ handleConnection(conn)// vieme vytvoriť len } // jedno spojenie na “server” } } net2/netserver.go

  6. HandleConnection funchandleConnection(connnet.Conn){ fmt.Println("handleConnection") r:=bufio.NewReader(conn)// wrapper na conn read stream for{ line,_,err:=r.ReadLine()// čítaj až do konca iferr==io.EOF{ break }// a píš na konzolu fmt.Printf("%s\n",line) } } net2/netserver.go

  7. Viacvláknový server funcmain(){ ln,err:=net.Listen("tcp",":8080") iferr!=nil{ fmt.Println("connectionerror:"+err.Error()) }else{ for{ conn,err:=ln.Accept() iferr!=nil{// server by mal prežiť !!! fmt.Println("error:"+err.Error()) continue }// obslúženie konekcie spustíme v nezávislej gohandleConnection(conn)// gorutine } } } net3/netserver.go

  8. Keď poznáme základy, skúsime vytvoriť jednoduchý chat-server umožnujúci: • viacero pripojení, • broadcastuje status všetkým ChatClient typeChatClientstruct{ clientIDint // poradové číslo klienta reader*bufio.Reader // reader a writer z/do konekcie writer*bufio.Writer // klienta } funcNewChatClient(clientIDint,connnet.Conn)*ChatClient{ return&ChatClient{// konštruktor vytvorí z ID a konekcie clientID:clientID, // ChatClient reader:bufio.NewReader(conn), writer:bufio.NewWriter(conn), } } net4/chatroom.go

  9. ChatRoom typeChatRoomstruct{// všetci ChatClienti clients[]*ChatClient } funcNewChatRoom()*ChatRoom{// prázdny ChatRoom chatRoom:=&ChatRoom{ clients:make([]*ChatClient,0), } returnchatRoom } func(chr*ChatRoom)NewChatClient(connnet.Conn)*ChatClient{ chatclient:=NewChatClient(len(chr.clients)+1,conn) fmt.Printf("newclient:%d\n",chatclient.clientID) chr.clients=append(chr.clients,chatclient) returnchatclient } net4/chatroom.go

  10. ChatRoom func(chr*ChatRoom)handleConnection(connnet.Conn){ chclient := chr.NewChatClient(conn) for{ line,_,err:=chclient.reader.ReadLine() iferr==io.EOF{ break } msg:=fmt.Sprintf("%d>%s\r\n",chclient.clientID,line) fmt.Print(msg)// výpis na konzolu chatroomu for_,client:=rangechr.clients{ ifclient.clientID!=chclient.clientID{ client.writer.WriteString(msg) client.writer.Flush() } }}} net4/chatroom.go

  11. ChatRoom v akcii net4/chatroom.go

  12. FTP Protokol Naprogramujeme časť FTP servera a klienta - podmnožinu FTP protokolu: • dir – obsah adresára • pwd – aktuálna cesta na serveri • cd newdir – zmeň aktuálnu cestu na serveri na newdir • put file – prenes lokálny súbor file na server • get file – prenes súbor file zo serveru do lokálneho adresára server na každú tcp-konekciu nezávisle zavolá gorutinu handleClient: read line from client for { switch line { ‘DIR’: send list directory to client ‘CD’ : change directory to newdir ‘PUT’: start file transfer from client } read line from client } client číta príkazy užívateľa a volá server read line from user for { switch line { ‘dir ....’: send ‘DIR …’ to server, display results ‘put ….’: send ‘PUT …’ to server and start file transfer file to server } read line from user }

  13. FTP server funchandleClient(connnet.Conn){ deferconn.Close()// ak nastane panika, zavri spojenie r:=bufio.NewReader(conn)// reader ku klientovi w:=bufio.NewWriter(conn)// writer for{ line,_,_:=r.ReadLine()// čítaj povel words:=strings.Split(string(line),"")// rozlož switchstrings.ToUpper(words[0]){// podľa prvého caseCD:// ak ‘CD’ ifos.Chdir(words[1])==nil{ // volaj os... s,_:=os.Getwd()// zisti aktuálny w.WriteString(s+"\r\n")// napíš klientovi }else{ w.WriteString("error\r\n")// ak neexistuje } ftpserver.go

  14. Skúška pomocou putty Problémy: • server si nepamätá lokálne hodnoty klienta, pwd... • autorizácia klienta • prenos súborov • šifrovanie obsahu ftpserver.go

  15. FTP klient funcmain(){// client socket sa pripojí na server conn,err:=net.Dial("tcp",host+":8080") stdior:=bufio.NewReader(os.Stdin)// príkazy užívateľa r:=bufio.NewReader(conn)// reader od ftp server w:=bufio.NewWriter(conn)// writer k ftp serveru for{ line,_,_:=stdior.ReadLine()// príkaz od usera words:=strings.Split(string(line),"") switchstrings.ToUpper(words[0]){ // podľa prvého caseCD: w.WriteString("CD"+words[1]+"\r\n") w.Flush() // povedz CD ftp serveru response,_,_:=r.ReadLine()// čítaj jeho ifstring(response)=="error"{// reakciu fmt.Println("Failedtochange ftpclient.go

  16. Skúška server-client

  17. HTTP client • GET Request-URI CRLF • [GET | HEAD | POST ] Request-URI HTTP-Version CRLF • GET http://google:80 HTTP/1.0 url:="http://google.com" response,err:=http.Head(url) fmt.Println(response.Status)// 200 OK fork,v:=rangeresponse.Header{ // Content-Type: fmt.Println(k+":",v)}// [text/html; charset=ISO-8859-2] response,err=http.Get(url) fmt.Println("\nbody:") reader:=bufio.NewReader(response.Body) for{ line,_,err:=reader.ReadLine() iferr==io.EOF{ break httpclient.go

  18. Čo s telom ? for{ line,_,err:=reader.ReadLine() iferr==io.EOF{break} strline:=string(line) varhttpRef=regexp.MustCompile( `(?i)href\s*=\s*(\"([^"]*\")|'[^']*'|([^'">\s]+))`) matches:=httpRef.FindAllString(strline,-1) for_,match:=rangematches{ fmt.Println(match) }} body: href="/search?" href="http://www.google.sk/imghp?hl=sk&tab=wi" href="http://maps.google.sk/maps?hl=sk&tab=wl" href="http://www.youtube.com/?gl=SK&tab=w1" href="https://mail.google.com/mail/?tab=wm" href="https://drive.google.com/?tab=wo" href="https://www.google.com/calendar?tab=wc" ... httpclient.go

  19. Crawlusesfetchertorecursivelycrawl pagesstartingwithurl,toamaximumofdepth WebCrawler TODO: FetchURLsinparallel. Don'tfetchthesameURLtwice. funcCrawl71(urlstring,depthint,fetcherFetcher){ ifdepth<=0{ return } body,urls,err:=fetcher.Fetch(url) iferr!=nil{ fmt.Println(err) return }// najivné prehľadávanie do hĺbky, bez kontroly fmt.Printf("found:%s%q\n",url,body) for_,u:=rangeurls{ Crawl71(u,depth-1,fetcher) } return } http://tour.golang.org/#71

  20. WebCrawling golang.org var fetcher = &fakeFetcher{ "http://golang.org/": &fakeResult{ "The Go Programming Language", []string{ "http://golang.org/pkg/", "http://golang.org/cmd/", }, }, "http://golang.org/pkg/": &fakeResult{ "Packages", []string{ "http://golang.org/", "http://golang.org/cmd/", "http://golang.org/pkg/fmt/", "http://golang.org/pkg/os/", }, }, "http://golang.org/pkg/fmt/": &fakeResult{ "Package fmt", []string{ "http://golang.org/", "http://golang.org/pkg/", }, }, "http://golang.org/pkg/os/": &fakeResult{ "Package os", []string{ "http://golang.org/", "http://golang.org/pkg/", }, }, } golang.org/pkg golang.org/os golang.org/cmd golang.org/pkg/fmt webcrawler.go

  21. WebCrawlerR // HashMap navštívených linkov varvisited=make(map[string]bool) funcCrawlR(urlstring,depthint,maxDepthint){ ifdepth<=maxDepth{// ak nie som príliš hlboko visited[url]=true // ok, bol som tu ... suburls:=crawlPageR(url,depth)// získaj urls for_,url:=rangesuburls.suburls{// prejdi ich if_,seen:=visited[url];seen{// ak si tam continue// bol, preskoč } CrawlR(url,depth+1,maxDepth)// inak rekurzia } } } [0:http://golang.org/] "The Go Programming Language" [1:http://golang.org/pkg/] "Packages" not found: http://golang.org/cmd/ [2:http://golang.org/pkg/fmt/] "Package fmt" [2:http://golang.org/pkg/os/] "Package os" webcrawler.go

  22. WebCrawlerR typeUrlsstruct{ depthint// hĺbka podstránky od koreňa suburls[]string// zoznam linkov na nej } funccrawlPageR(urlstring,depthint)*Urls{ body,urls,err:=fetcher.Fetch(url)// toto nemáme iferr!=nil{ fmt.Println(err) }else{ fmt.Printf("found[%d:%s]%q\n",depth,url,body) } return&Urls{depth+1,urls} } webcrawler.go

  23. WebCrawler 2 var( // akonáhle prejdeme stránkus adresou url, všetky jej vnorené Urls zapíšeme ho do kanálu globalQueueOfUrls=make(chanUrls) totalRuns=0 // počet spustení crawlPage // t.j. veľkosť fronty nespracovaných Urls visited=make(map[string]bool)// navštívené urls ) funccrawlPage(urlstring,depthint){ body,urls,err:=fetcher.Fetch(url) if err ... fmt.Printf("[%d:%s]%q\n",depth,url,body) globalQueueOfUrls<-Urls{depth+1,urls} } webcrawler.go

  24. WebCrawler 2 funcCrawl(urlstring,depthint){ totalRuns++ // spracuj hlavnú stránku visited[url]=true // navštívili sme ju gocrawlPage(url,0)// pridaj jej Urls do fronty fortotalRuns>0{ // kým je niečo vo fronte totalRuns--// dekrementuj veľkosť fronty next:=<-globalQueueOfUrls // vyber z fronty ifnext.depth>depth{continue}// prihlboko for_,url:=rangenext.suburls{// do hĺbky if_,seen:=visited[url];seen{continue } visited[url]=true totalRuns++ // nerekurzívne spracuj gocrawlPage(url,next.depth)// podstránky }}} webcrawler.go

  25. Web1 packagemain import("fmt""net/http") type Handler interface { ServeHTTP(w ResponseWriter, r *Request)} typeFooint//FooimplementsHandler func(hFoo)ServeHTTP(whttp.ResponseWriter,r*http.Request){ fmt.Println(r.Header["User-Agent"]) fmt.Println(r.Host)// servlet, cgi-script fmt.Fprintf(w,"Foo!") } funcmain(){ varhFoo http.ListenAndServe("localhost:8080",h) } Zdroj:http://golang.org/doc/articles/wiki/

  26. Web2 http.HandleFunc("/view/",viewHandler) http.HandleFunc("/edit/",editHandler) http.ListenAndServe(":8080",nil) • typePagestruct{ Titlestring Body[]byte } • func(p*Page)savePage()error// uloží stránku na server • funcloadPage(titlestring)(*Page,error)// načíta • funcviewHandler(whttp.ResponseWriter,r*http.Request){ title:=r.URL.Path[len("/view/"):] p,_:=loadPage(title) fmt.Fprintf(w,"<h1>%s</h1><div>%s</div>", p.Title,p.Body) } • funceditHandler(whttp.ResponseWriter,r*http.Request) Zdroj:http://golang.org/doc/articles/wiki/

  27. MiniWiki funcviewHandler(whttp.ResponseWriter, r*http.Request,titlestring){ p,err:=loadPage(title) iferr!=nil{ http.Redirect(w,r,"/edit/"+title,http.StatusFound) return }  t, err1 :=template.ParseFiles("view.html") err2 := t.Execute(w,p) } funcsaveHandler(whttp.ResponseWriter, r*http.Request,titlestring){ body:=r.FormValue("body") p:=&Page{Title:title,Body:[]byte(body)} err:=p.save() ... Zdroj:http://golang.org/doc/articles/wiki/

More Related