38
Klobúky ako predjedlo (čo to má s programovaním pochopíte dnes) 3 biele a 2 čierne A, B, C si navzájom vidia farby klobúkov nesmú komunikovať, ale (aj tak) sú inteligentní vyhrávajú, ak všetci uhádnu farbu svojho klobúka resp. ak sa jeden pomýli, prehrali všetci. Hint: A,B,C sú spoluhráči, preto predpokladaj, že sú chytrí a mysli aj za nich Hint: úloha nie je o šťastí=hádaní správneho riešenia

Go networking

  • Upload
    callie

  • View
    75

  • Download
    0

Embed Size (px)

DESCRIPTION

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 - PowerPoint PPT Presentation

Citation preview

Page 1: Go  networking

Klobúky ako predjedlo(čo to má s programovaním pochopíte dnes)

3 biele a 2 čierne A, B, C si navzájom vidia farby klobúkov nesmú komunikovať, ale (aj tak) sú inteligentní vyhrávajú, ak všetci uhádnu farbu svojho klobúka resp. ak sa jeden pomýli, prehrali všetci.

Hint: A,B,C sú spoluhráči, preto predpokladaj, že sú chytrí a mysli aj za nich

Hint: úloha nie je o šťastí=hádaní správneho riešenia

Page 2: Go  networking

Do 10 sekúndak vidím dva čierne, určite mám biely, a

preto sa hneď ozvem, že "mám biely".

ak sa niekto do 10s ozval, že má biely, musí vidieť dva čierne, preto ja mám čierny, tak hneď kričím "mám čierny".

inak čakám 10s, nikto neozval, že „mám biely", preto určite nie sú v hre 2 čierne, ale najviac jeden čierny !!!

Page 3: Go  networking

10 až 20 sekúnd

ak teda vidím čierny, ja musím mať biely, tak sa ozvem hneď, že mám "mám biely".

inak, ak sa ozvú dvaja (do 10 s), že biely, ja mám čierny,

tak kričím "mám čierny".

inak, nevidím čierny a nikto sa neozval, čakám ďalších 10s,

v hre je najviac jeden čierny

Page 4: Go  networking

po 20 sekundách

keďže sa nikto neozval, tak nie je žiaden čierny, tak kričím "mám biely" a ostatní tiež

v hre nie je žiaden čierny

Page 5: Go  networking

Celý algoritmus(bez vysvetlenia, už pre cvičenú opicu)

ak vidím dva čierne, hneď ozvem, že "mám biely".

ak sa niekto do 10 s ozval, tak kričím "mám čierny".

inak čakám 10s.

ak vidím čierny, tak hneď kričím "mám biely".

inak, ak sa ozvú dvaja do 10 s, tak kričím "mám čierny".

Po 10 sek:

inak čakám ďalších 10s,

kričím "mám biely”

Po 20 sek:

Hneď:

Page 6: Go  networking

Na zamyslenie je podstatné, či kričím mám biely/mám čierny, nestačí len už

viem ?!

Dalo by sa to pre 3 biele, 3 čierne, 3 ľudia ?

Dalo by sa to pre 2 biele, 1 čierne, 2 ľudia ?

Dalo by sa to pre N biele, (N-1) čierne, N ľudia ? (napr.6,5,6)

Dalo by sa to pre >N biele, (N-1) čierne, N ľudia ? (napr. 8,5,6)

Dalo by sa to pre N biele, <(N-1) čierne, N ľudia ? (napr. 6,4,6)

Page 7: Go  networking

Komunikácia–každý s každým

Page 8: Go  networking

Správa, kanály, agentitype Message struct {     who int     // od koho, odosielateľ

what int } // čo, obsah správyfunc makeChannels(n int) []chan Message {     chArray := make([]chan Message, n)    for i:= 0; i < n; i++ {// kanál,na ktorom počúva i-ty agent        chArray[i] = make(chan Message)     }     return chArray } func main() {     chArray := makeChannels(numb)     for a:= 0; a<numb; a++ {         runAgent(a, chArray) } }

klobuky/modelBezDispecher.go

Page 9: Go  networking

Agenti napriamofunc runAgent(agent int, channels []chan Message) {     

go func() { // ID agenta, kanaly na vsetkych agentov      i := 1 // iniciálny stav agenta      for { // loop forever       timeout := time.After(...)        select {          case msg := <- channels[agent]: // agent počúva len svoj           fmt.Printf("agentovi %d: prišla správa:%s",agent, msg)          case <-timeout: // prešiel timeout, vyrobíme správu msg           msg := Message{who:agent, what:i++} //zmeníme svoj stav

for index, ch := range channels { // povedz každému             if index != agent {         // okrem seba                  go func(cha chan Message) {// !!!!!!!!!!!!!!!!                      cha <- msg // správu msg                  }(ch)

klobuky/modelBezDispecher.go

Page 10: Go  networking

Agenti napriamofunc runAgent(agent int, channels []chan Message) {     

go func() { // ID agenta, kanaly na vsetkych agentov      i := 1 // iniciálny stav agenta      for { // loop forever       timeout := time.After(...)        select {          case msg := <- channels[agent]: // agent počúva len svoj           fmt.Printf("agentovi %d: prišla správa:%s",agent, msg)          case <-timeout: // prešiel timeout, vyrobíme správu msg           msg := Message{who:agent, what:i++} //zmeníme svoj stav

for index, ch := range channels { // povedz každému             if index != agent {         // okrem seba                  go func() { // !!!!! ZLE !!!!!!                      ch <- msg // správu msg                  }()

klobuky/modelBezDispecher.go

Page 11: Go  networking

Príklad komunikácie 3 agentov1: povedal 1

agentovi 2: prisla sprava:"1: povedal 1"

agentovi 0: prisla sprava:"1: povedal 1"

0: povedal 1

agentovi 2: prisla sprava:"0: povedal 1"

agentovi 1: prisla sprava:"0: povedal 1"

1: povedal 2

agentovi 2: prisla sprava:"1: povedal 2"

0: povedal 2

1: povedal 3

agentovi 0: prisla sprava:"1: povedal 2"

agentovi 0: prisla sprava:"1: povedal 3"

agentovi 1: prisla sprava:"0: povedal 2"

agentovi 2: prisla sprava:"0: povedal 2"

agentovi 2: prisla sprava:"1: povedal 3“

Page 12: Go  networking

Aplikácia na klobúky(domáca úloha)

[0s] A: vidim 1 biele a 1 cierne [0s] A: cakam 10 sek [0s] C: vidim 1 biele a 1 cierne [0s] C: cakam 10 sek [0s] B: vidim 2 biele a 0 cierne [0s] B: cakam 10 sek

[10s] B: cakam dalsich 10 sek [11s] A: mam biely !!! true [11s] C: mam biely !!! true [11s] B:: prisla sprava, ze [11s] A: mam biely !!! true [12s] B: mam cierny !!! true finito

func vidim(name String) (int, int) {

Page 13: Go  networking

Komunikácia s dispečerom

Page 14: Go  networking

Dispatcher čo počujte to prepošle

func runDispatcher(channels []chan Message) chan Message {  dispch := make(chan Message)        // kanál na komunikáciu s dispatcherom   go func() {     for {       msg := <- dispch // ak prišla správa      fmt.Println("dispecer sa dozvedel: " +

msg.toString())       for _,ch := range channels {         go func(x chan Message) { 

x <- msg        }(ch)      }     }   }()  return dispch }      klobuky/modelSDispecher.go

Page 15: Go  networking

Agenti cez dispečerafunc runAgentCommunicatingWithDispatcher(agent int,

dispch chan Message, input chan Message) {      go func() {    i := 0    // stav agenta          for {      timeout := time.After(...) // náhodny delay       select {         case msg := <- input: // ak prišla správa agentovi,           fmt.Printf("agentovi %d: prisla sprava:%s",agent,msg)

case <-timeout:   // po timeout, vytvoríme správu          msg := Message{who:agent, what:i}            dispch <- msg   // pošleme dispecerovi           i++        // agent si zvýši stav } } }() }

klobuky/modelSDispecher.go

Page 16: Go  networking

Agenti cez dispečerafunc runAgentCommunicatingWithDispatcher(agent int,

dispch chan Message, input chan Message) {     go func() {    i := 0    // stav agenta          for {      timeout := time.After(...) // náhodny delay       select {         case msg := <- input: // ak prišla správa agentovi,           fmt.Printf("agentovi %d: prisla sprava:%s",agent,msg)

case <-timeout:   // po timeout, vytvoríme správu          msg := Message{who:agent, what:i}  

          go func() { dispch <- msg }()// pošleme dispecerovi           i++        // agent si zvýši stav } } }() }

klobuky/modelSDispecher.go

Page 17: Go  networking

Príklad komunikácie 3 agentov1: povedal 0

dispecer sa dozvedel: 1: povedal 0

agentovi 2: prisla sprava:"1: povedal 0"

agentovi 0: prisla sprava:"1: povedal 0"

agentovi 1: prisla sprava:"1: povedal 0"

0: povedal 0

dispecer sa dozvedel: 0: povedal 0

agentovi 2: prisla sprava:"0: povedal 0"

agentovi 0: prisla sprava:"0: povedal 0"

agentovi 1: prisla sprava:"0: povedal 0"

0: povedal 1

dispecer sa dozvedel: 0: povedal 1

agentovi 2: prisla sprava:"0: povedal 1"

agentovi 0: prisla sprava:"0: povedal 1"

agentovi 1: prisla sprava:"0: povedal 1“

Page 18: Go  networking

Aplikácia na klobúky(domáca úloha) [0s] A: vidim 1 biele a 1 cierne [0s] A: cakam 10 sek [0s] B: vidim 2 biele a 0 cierne [0s] B: cakam 10 sek [0s] C: vidim 1 biele a 1 cierne [0s] C: cakam 10 sek [10s] B: cakam dalsich 10 sek [11s] A: mam biely !!! true od A prisla sprava, ze [11s] A: mam biely !!! true [11s] C: mam biely !!! true [11s] B:: prisla sprava, ze [11s] A: mam biely !!! True od C prisla sprava, ze [11s] A: mam biely !!! true od B prisla sprava, ze [11s] A: mam biely !!! true od B prisla sprava, ze [11s] C: mam biely !!! true [12s] B: mam cierny !!! True finito

func vidim(name String) (int, int) {

Page 19: 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) Webcrawler

Zdroje: http://golang.org/doc/articles/wiki/ http://jan.newmarch.name/go

Page 20: Go  networking

Client socketimport ( "bufio"     "fmt"     "io"     "net" ) func main() { // vytvorenie spojenia socket-socket conn, err := net.Dial("tcp", "google.com:80")     if err != nil {         fmt.Println("connection error: " + 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            if err == io.EOF {                 break             }             fmt.Printf("%s\n", line)         }     } }

net1/netclient1.go

Page 21: Go  networking

Pomocou putty

Page 22: Go  networking

Sntp klient    conn, err := net.Dial("udp","0.sk.pool.ntp.org:123")

    if err != 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))

    defer conn.Close()

    w.Write(data) // send request  

    w.Flush()

    data, _, err = r.ReadLine() // read response     var sec, frac uint64

     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("Network time: %v\n", t)

sntp/sntpclient.go

RFC 4330http://tools.ietf.org/html/rfc4330

Page 23: Go  networking

Jednovláknový serverimport ( "bufio" "fmt" "io" "net" )

func main() { // porty <1024 majú špeciálne určenie

    ln, err := net.Listen("tcp", ":8080") // server socket

    if err != nil {

        fmt.Println("connection error: " + err.Error())

    } else {

        conn, err := ln.Accept() // blokuje kým ja niekto

        if err != nil { // nepokúsi o spojenie

            fmt.Println("error: " + err.Error())

        } else {

            handleConnection(conn) // vieme vytvoriť len

        } // jedno spojenie na “server”

    }

}net2/netserver.go

Page 24: Go  networking

HandleConnectionfunc handleConnection(conn net.Conn) {

    fmt.Println("handleConnection")

    r := bufio.NewReader(conn)// wrapper na conn read stream

    for {

        line, _, err := r.ReadLine() // čítaj až do konca

        if err == io.EOF {

            break

        } // a píš na konzolu

        fmt.Printf("%s\n", line)

    }

}

net2/netserver.go

Page 25: Go  networking

Viacvláknový serverfunc main() {

    ln, err := net.Listen("tcp", ":8080")

    if err != nil {

        fmt.Println("connection error: " + err.Error())

    } else {

        for {

            conn, err := ln.Accept()

            if err != nil { // server by mal prežiť !!!

                fmt.Println("error: " + err.Error())

                continue

            } // obslúženie konekcie spustíme v nezávislej

            go handleConnection(conn) // gorutine

        }

    }

} net3/netserver.go

Page 26: Go  networking

ChatClient

type ChatClient struct {

    clientID int // poradové číslo klienta

    reader *bufio.Reader // reader a writer z/do konekcie

    writer *bufio.Writer // klienta

}

func New_ChatClient(clientID int, conn net.Conn) *ChatClient {

    return &ChatClient{// konštruktor vytvorí z ID a konekcie

        clientID: clientID, // ChatClient

        reader: bufio.NewReader(conn),

        writer: bufio.NewWriter(conn),

    }

}

Keď poznáme základy, skúsime vytvoriť jednoduchý chat-server umožnujúci: •viacero pripojení, •broadcastuje status všetkým

net4/chatroom.go

Page 27: Go  networking

ChatRoomtype ChatRoom struct { // všetci ChatClienti

    clients []*ChatClient

}

func NewChatRoom() *ChatRoom {// prázdny ChatRoom

    chatRoom := &ChatRoom{

        clients: make([]*ChatClient, 0),

   }

    return chatRoom

}

func (chr *ChatRoom) NewChatClient(conn net.Conn) *ChatClient {

    chatclient := New_ChatClient(len(chr.clients)+1, conn)  

   fmt.Printf("new client: %d\n", chatclient.clientID)

    chr.clients = append(chr.clients, chatclient)  

   return chatclient

}

net4/chatroom.go

Page 28: Go  networking

ChatRoomfunc (chr *ChatRoom) handleConnection(conn net.Conn) {

   chclient := chr.NewChatClient(conn) for {

     line, _, err := chclient.reader.ReadLine()

     if err == io.EOF {

        break

     }

     msg := fmt.Sprintf("%d>%s\r\n", chclient.clientID,line)

     fmt.Print(msg)    // výpis na konzolu chatroomu

     for _, client := range chr.clients {

        if client.clientID != chclient.clientID {

           client.writer.WriteString(msg)

           client.writer.Flush()             

}

 } } }

net4/chatroom.go

Page 29: Go  networking

ChatRoom v akcii

net4/chatroom.go

Page 30: Go  networking

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

  for k, v := range response.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()

        if err == io.EOF {

            break   

httpclient.go

Page 31: Go  networking

Čo s telom ?  for {

      line, _, err := reader.ReadLine()

      if err == io.EOF { break }

      strline := string(line)         

var httpRef = regexp.MustCompile(

`(?i)href\s*=\s*(\"([^"]*\")|'[^']*'|([^'">\s]+))`)  

       matches := httpRef.FindAllString(strline, -1)

       for _, match := range matches {

         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

Page 32: Go  networking

WebCrawlerfunc Crawl71(url string, depth int, fetcher Fetcher) {

    if depth <= 0 {  

       return

    }

    body, urls, err := fetcher.Fetch(url)

    if err != nil {

        fmt.Println(err)

        return

    } // najivné prehľadávanie do hĺbky, bez kontroly

    fmt.Printf("found: %s %q\n", url, body)

    for _, u := range urls {

        Crawl71(u, depth-1, fetcher)

    }

    return

}

Crawl uses fetcher to recursively crawl pages starting with url, to a maximum of depth

TODO: Fetch URLs in parallel. Don't fetch the same URL twice.

http://tour.golang.org/concurrency/9

Page 33: Go  networking

WebCrawlingvar 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

golang.org/pkg

golang.org/pkg/fmt

golang.org/os

golang.org/cmd

webcrawler.go

Page 34: Go  networking

WebCrawlerR // HashMap navštívených linkov

var visited = make(map[string]bool)

func CrawlR(url string, depth int, maxDepth int) {

    if depth <= maxDepth {// ak nie som príliš hlboko

        visited[url] = true // ok, bol som tu ...

        suburls := crawlPageR(url, depth) // získaj urls

        for _, url := range suburls.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

Page 35: Go  networking

WebCrawlerRtype Urls struct {

    depth int // hĺbka podstránky od koreňa

    suburls []string // zoznam linkov na nej

}

func crawlPageR(url string, depth int) *Urls {

    body, urls, err := fetcher.Fetch(url) // toto nemáme    if err != nil {

        fmt.Println(err)

    } else {

        fmt.Printf("found[%d:%s] %q\n", depth, url, body)

    }

    return &Urls{depth + 1, urls}

}

webcrawler.go

size: 2871m27.4049993s

Page 36: Go  networking

var (

// akonáhle prejdeme stránku s adresou url, všetky jej vnorené Urls zapíšeme ho do kanálu

    globalQueueOfUrls = make(chan Urls)

    totalRuns = 0 // počet spustení crawlPage

// t.j. veľkosť fronty nespracovaných Urls

    visited = make(map[string]bool) // navštívené urls

)

func crawlPage(url string, depth int) {

    body, urls, err := fetcher.Fetch(url)

if err ...

    fmt.Printf("[%d:%s] %q\n", depth, url, body)

    globalQueueOfUrls <- Urls{depth + 1, urls}

}

WebCrawler 2

webcrawler.go

Page 37: Go  networking

func Crawl(url string, depth int) {

    totalRuns++ // spracuj hlavnú stránku

    visited[url] = true // navštívili sme ju

    go crawlPage(url, 0) // pridaj jej Urls do fronty

    for totalRuns > 0 { // kým je niečo vo fronte

        totalRuns-- // dekrementuj veľkosť fronty

        next := <-globalQueueOfUrls // vyber z fronty

        if next.depth > depth { continue } // prihlboko

        for _, url := range next.suburls { // do hĺbky

            if _, seen := visited[url]; seen { continue }

            visited[url] = true

            totalRuns++ // nerekurzívne spracuj

            go crawlPage(url, next.depth) // podstránky

}   } }

WebCrawler 2

webcrawler.go

size: 2877.6544378s

Page 38: Go  networking

Riešenia je podstatné, či kričím mám biely/mám čierny, stačí len „už viem“ ?!

áno Dalo by sa to pre 3 biele, 3 čierne, 3 ľudia ?

nie Dalo by sa to pre 2 biele, 1 čierne, 2 ľudia ?

áno Dalo by sa to pre N biele, (N-1) čierne, N ľudia ? (napr.6,5,6)

áno Dalo by sa to pre >N biele, (N-1) čierne, N ľudia ? (napr.

8,5,6)

áno Dalo by sa to pre N biele, <(N-1) čierne, N ľudia ? (napr.

6,4,6)

áno