Detaillierte Erläuterung der Go-Netzwerkprogrammierung

Eine Einführung in das Internetprotokoll

1.1 Internet-Schichtenmodell

Die logische Implementierung des Internets ist in mehrere Schichten unterteilt. Jede Etage hat ihre eigene Funktion und wie bei einem Gebäude wird jede Etage von der darunter liegenden Etage getragen. Was der Benutzer berührt, ist nur die oberste Schicht, die unteren Schichten sind überhaupt nicht zu spüren. Um das Internet zu verstehen, müssen Sie die Funktionen jeder Ebene von Grund auf verstehen.
Fügen Sie hier eine Bildbeschreibung ein

Wie in der Abbildung oben gezeigt, wird das Internet nach unterschiedlichen Modellen in verschiedene Schichten unterteilt. Unabhängig davon, welches Modell zur Unterteilung verwendet wird, gilt: Je höher die Schicht, desto näher am Benutzer und desto niedriger die Schicht , desto näher ist es an der Hardware. In der Softwareentwicklung verwenden wir am häufigsten das Modell, das das Internet in der obigen Abbildung in fünf Schichten unterteilt.

Als nächstes führen wir jede Schicht Schicht für Schicht von unten nach oben ein.

physikalische Schicht

Unser Computer muss mit dem externen Internet kommunizieren. Wir müssen den Computer zuerst mit dem Netzwerk verbinden. Wir können Twisted Pair, Glasfaser, Funkwellen und andere Methoden verwenden. Dies wird als „reale physikalische Schicht“ bezeichnet und ist die physische Verbindung von Computern miteinander. Es spezifiziert hauptsächlich einige elektrische Eigenschaften des Netzwerks und ist für die Übertragung der elektrischen Signale 0 und 1 verantwortlich.

Datenübertragungsebene

Reine 0 und 1 haben keine Bedeutung, daher geben unsere Benutzer ihnen einige spezifische Bedeutungen und legen die Art und Weise der Interpretation elektrischer Signale fest: zum Beispiel: Wie viele elektrische Signale zählen als Gruppe? Welche Bedeutung haben die einzelnen Signalbits? Dies ist die Funktion der „Datenverbindungsschicht“, die über der „physikalischen Schicht“ liegt und die Gruppierungsmethode und die repräsentative Bedeutung von 0 und 1 bestimmt, die von der physikalischen Schicht übertragen werden. In der Anfangszeit hatte jedes Unternehmen seine eigene Art, elektrische Signale zu gruppieren. Nach und nach übernahm ein Protokoll namens „Ethernet“ (Ethernet) die Führung.

Ethernet schreibt vor, dass eine Gruppe elektrischer Signale ein Datenpaket bildet, das als „Frame“ bezeichnet wird. Jeder Frame ist in zwei Teile unterteilt: Header (Head) und Daten (Data). Darunter enthält „Header“ einige Beschreibungselemente des Datenpakets, wie Absender, Empfänger, Datentyp usw.; „Daten“ ist der spezifische Inhalt des Datenpakets. Die Länge des „Headers“ ist auf 18 Byte festgelegt. Die Länge der „Daten“ beträgt 46 Byte, die längste 1500 Byte. Daher ist der gesamte „Frame“ nur 64 Bytes kurz und 1518 Bytes lang. Wenn die Daten sehr lang sind, müssen sie zur Übertragung in mehrere Frames aufgeteilt werden.

Wie werden nun Sender und Empfänger identifiziert? Ethernet schreibt vor, dass alle an das Netzwerk angeschlossenen Geräte über eine „Netzwerkkarten“-Schnittstelle verfügen müssen. Pakete müssen von einer NIC an eine andere gesendet werden. Die Adresse der Netzwerkkarte ist die Sendeadresse und Empfangsadresse des Datenpakets, die als MAC-Adresse bezeichnet wird. Wenn jede Netzwerkkarte das Werk verlässt, verfügt sie über eine weltweit einzigartige MAC-Adresse mit einer Länge von 48 Binärbits, die normalerweise durch 12 Hexadezimalzahlen dargestellt wird. Die ersten 6 Hexadezimalzahlen sind die Seriennummer des Herstellers und die letzten 6 sind die Seriennummer der Netzwerkkarte des Herstellers. Anhand der MAC-Adresse lässt sich die Netzwerkkarte und der Pfad des Datenpakets lokalisieren.

Wir erhalten die MAC-Adresse des Empfängers über das ARP-Protokoll. Wie können die Daten nach Erhalt der MAC-Adresse genau an den Empfänger gesendet werden? Tatsächlich verwendet Ethernet hier eine sehr „primitive“ Methode. Es sendet das Datenpaket nicht genau an den Empfänger, sondern an alle Computer im Netzwerk, sodass jeder Computer den „Header“ des Pakets lesen kann. , Suchen Sie die MAC-Adresse des Empfängers und vergleichen Sie sie dann mit seiner eigenen MAC-Adresse. Wenn beide identisch sind, akzeptieren Sie das Paket zur weiteren Verarbeitung, andernfalls verwerfen Sie das Paket. Diese Art des Sendens wird als „Broadcasting“ bezeichnet.

Netzwerkschicht

Gemäß den Regeln des Ethernet-Protokolls können wir uns beim Versenden von Daten auf die MAC-Adresse verlassen. Theoretisch kann die Netzwerkkarte Ihres Computers mithilfe der MAC-Adresse die Netzwerkkarte eines Computers in einer anderen Ecke der Welt finden. Dieser Ansatz weist jedoch einen großen Fehler auf: Ethernet verwendet Broadcasting zum Senden von Datenpaketen und alle Mitglieder arbeiten Hand in Hand . Packet“ ist nicht nur ineffizient, sondern die gesendeten Daten können auch nur auf das Subnetz beschränkt werden, in dem sich der Absender befindet. Das heißt, wenn sich die beiden Computer nicht im selben Subnetz befinden, kann die Übertragung nicht übertragen werden. Dieses Design ist sinnvoll und notwendig, da es unrealistisch ist, wenn jeder Computer im Internet alle im Internet gesendeten und empfangenen Datenpakete empfängt.

Daher muss eine Möglichkeit gefunden werden, zu unterscheiden, welche MAC-Adressen zum selben Subnetz gehören und welche nicht. Wenn es sich um dasselbe Subnetz handelt, wird es per Broadcast gesendet, andernfalls per „Routing“. Dies führte zur Geburt der „Netzwerkschicht“. Seine Funktion besteht darin, einen neuen Satz von Adressen einzuführen, damit wir unterscheiden können, ob verschiedene Computer zum selben Subnetz gehören. Dieser Satz von Adressen wird „Netzwerkadresse“ oder kurz „URL“ genannt.

Nach dem Aufkommen der „Netzwerkschicht“ verfügt jeder Computer über zwei Arten von Adressen, eine ist die MAC-Adresse und die andere ist die Netzwerkadresse. Es besteht keine Verbindung zwischen den beiden Adressen. Die MAC-Adresse ist an die Netzwerkkarte gebunden und die Netzwerkadresse wird vom Netzwerkadministrator zugewiesen. Mithilfe der Netzwerkadresse können wir feststellen, in welchem ​​Subnetz sich der Computer befindet, und die MAC-Adresse sendet das Paket an die Ziel-NIC in diesem Subnetz. Daraus lässt sich logisch schließen, dass zuerst die Netzwerkadresse und dann die MAC-Adresse verarbeitet werden muss.

Das Protokoll, das die Netzwerkadresse angibt, wird als IP-Protokoll bezeichnet. Die darin definierte Adresse wird als IP-Adresse bezeichnet. Derzeit ist die vierte Version des IP-Protokolls, IPv4 genannt, weit verbreitet. Diese Version von IPv4 schreibt vor, dass eine Netzwerkadresse aus 32 Binärziffern besteht. Normalerweise verwenden wir Dezimalzahlen, die in vier Segmente unterteilt sind, um IP-Adressen von 0.0.0.0 bis 255.255.255.255 darzustellen.

Die gemäß dem IP-Protokoll gesendeten Daten werden als IP-Paket bezeichnet. Das IP-Paket ist ebenfalls in zwei Teile unterteilt: „Header“ und „Daten“: Der „Header“-Teil enthält hauptsächlich Informationen wie Version, Länge, IP-Adresse usw. und der „Daten“-Teil ist der spezifische Inhalt des IP-Datenpaket. Die Länge des „Header“-Teils des IP-Datenpakets beträgt 20 bis 60 Byte, die Gesamtlänge des gesamten Datenpakets beträgt maximal 65535 Byte.

Transportschicht

Mit der MAC-Adresse und der IP-Adresse können wir bereits eine Kommunikation zwischen zwei beliebigen Hosts im Internet herstellen. Das Problem besteht jedoch darin, dass sich auf demselben Host viele Programme befinden, die das Netzwerk zum Senden und Empfangen von Daten verwenden müssen. Beispielsweise müssen beide Programme, QQ und der Browser, eine Verbindung zum Internet herstellen und Daten senden und empfangen. Wie Unterscheiden wir, zu welchem ​​Programm ein bestimmtes Datenpaket gehört? Mit anderen Worten: Wir benötigen auch einen Parameter, der angibt, für welches Programm (Prozess) dieses Datenpaket bestimmt ist. Dieser Parameter wird als „Port“ (Port) bezeichnet und ist eigentlich die Nummer jedes Programms, das die Netzwerkkarte verwendet. Jedes Datenpaket wird an einen bestimmten Port des Hosts gesendet, sodass verschiedene Programme die benötigten Daten erhalten können.

„Port“ ist eine Ganzzahl zwischen 0 und 65535, genau 16 Binärbits. Ports von 0 bis 1023 sind vom System belegt und Benutzer können nur Ports größer als 1023 auswählen. Mit IP und Port können wir ein Programm im Internet eindeutig bestimmen und dann die Programmkommunikation zwischen Netzwerken realisieren.

Wir müssen dem Paket Portinformationen hinzufügen, was ein neues Protokoll erfordert. Die einfachste Implementierung heißt UDP-Protokoll und ihr Format steht fast vor den Daten plus der Portnummer. Ein UDP-Paket besteht ebenfalls aus zwei Teilen: „Header“ und „Daten“. Der „Header“-Teil definiert hauptsächlich den Sendeport und den Empfangsport, und der „Daten“-Teil ist der spezifische Inhalt. Das UDP-Paket ist sehr einfach: Der „Header“-Teil hat insgesamt nur 8 Bytes und die Gesamtlänge überschreitet nicht 65.535 Bytes, was in ein IP-Paket passt.

Der Vorteil des UDP-Protokolls besteht darin, dass es relativ einfach und leicht zu implementieren ist, der Nachteil besteht jedoch in der geringen Zuverlässigkeit. Sobald das Datenpaket gesendet wurde, ist es unmöglich zu wissen, ob die andere Partei es empfangen hat. Um dieses Problem zu lösen und die Netzwerkzuverlässigkeit zu verbessern, wurde das TCP-Protokoll geboren. Das TCP-Protokoll kann sicherstellen, dass keine Daten verloren gehen. Seine Nachteile sind ein komplexer Prozess, eine schwierige Implementierung und ein hoher Ressourcenverbrauch. Für TCP-Datenpakete gibt es keine Längenbeschränkung, theoretisch kann sie unendlich lang sein. Um jedoch die Effizienz des Netzwerks sicherzustellen, überschreitet normalerweise die Länge von TCP-Datenpaketen nicht die Länge von IP-Datenpaketen, um sicherzustellen, dass ein einzelnes TCP Das Datenpaket muss nicht geteilt werden.

Anwendungsschicht

Die Anwendung empfängt die Daten von der „Transportschicht“ und der nächste Schritt besteht darin, die Daten zu entpacken. Da es sich beim Internet um eine offene Architektur mit verschiedenen Datenquellen handelt, muss das Datenformat der Kommunikation vorab festgelegt werden, da der Empfänger sonst nicht in der Lage ist, den tatsächlich gesendeten Dateninhalt zu erhalten. Die Rolle der „Anwendungsschicht“ besteht darin, das von der Anwendung verwendete Datenformat anzugeben, z. B. die gängigen Protokolle E-Mail, HTTP, FTP und andere zusätzlich zu unserem TCP-Protokoll. Diese Protokolle bilden die Anwendungsschicht des Internetprotokolls.

Wie in der folgenden Abbildung dargestellt, fügen die HTTP-Daten des Absenders während des Übertragungsprozesses der HTTP-Daten über das Internet nacheinander die Header-Informationen jeder Schicht des Protokolls hinzu, und der Empfänger entpackt die Daten anschließend entsprechend dem Protokoll Empfangen des Datenpakets.
Fügen Sie hier eine Bildbeschreibung ein

Zwei-Socket-Programmierung

Socket ist der Prozesskommunikationsmechanismus von BSD UNIX und wird allgemein auch als „Socket“ bezeichnet. Es wird zur Beschreibung der IP-Adresse und des Ports verwendet und ist das Handle einer Kommunikationskette. Unter Socket kann die API des TCP/IP-Netzwerks verstanden werden, die viele Funktionen oder Routinen definiert, und Programmierer können damit Anwendungen im TCP/IP-Netzwerk entwickeln. Auf dem Computer ausgeführte Anwendungen senden normalerweise Anfragen an das Netzwerk oder antworten auf Netzwerkanfragen über „Sockets“.

Steckdosendiagramm

Socket ist eine zwischengeschaltete Software-Abstraktionsschicht für die Kommunikation zwischen der Anwendungsschicht und der TCP/IP-Protokollfamilie. Im Entwurfsmodus ist Socket eigentlich ein Fassadenmodus, der die komplexe TCP/IP-Protokollfamilie hinter Socket verbirgt. Für Benutzer müssen sie nur die von Socket angegebenen relevanten Funktionen aufrufen, damit Socket Daten organisieren kann, die dem angegebenen Protokoll entsprechen Fahren Sie dann mit der Kommunikation fort.
Fügen Sie hier eine Bildbeschreibung ein

  • Socket wird auch als „Socket“ bezeichnet. Anwendungen senden normalerweise Anfragen an das Netzwerk oder antworten auf Netzwerkanfragen über „Sockets“.
  • Es gibt zwei häufig verwendete Socket-Typen: Streaming-Socket und Datagramm-Socket. Streaming ist ein verbindungsorientierter Socket für verbindungsorientierte TCP-Dienstanwendungen, und Datagramm-Socket ist ein verbindungsloser Socket für verbindungslose UDP-Dienstanwendungen
  • TCP: zuverlässiger, verbindungsorientierter, langsamer
  • UDP: nicht zu zuverlässig, schneller

Zum Beispiel: TCP ist wie eine Expresszustellung per Nachnahme. Sie müssen Sie sehen, wenn Sie zu Hause ankommen, um als vollständiger Vorgangssatz zu gelten. UDP ist wie ein Kurier-Express-Kabinett. Werfen Sie es einfach weg und Sie erhalten es nicht. Im Allgemeinen wird UDP für Live-Übertragungen verwendet.

Drei TCP-Programmierung

Die Go-Sprache implementiert die TCP-Kommunikation

TCP-Protokoll

TCP/IP (Transmission Control Protocol/Internet Protocol), also Transmission Control Protocol/Internet Protocol, ist ein verbindungsorientiertes (verbindungsorientiertes), zuverlässiges, Byte-Stream-basiertes Kommunikationsprotokoll der Transportschicht (Transportschicht), weil Es handelt sich um ein verbindungsorientiertes Protokoll. Daten werden wie ein Wasserfluss übertragen und es gibt Sticky-Pakete.

TCP-Server

Ein TCP-Server kann sich mit vielen Clients gleichzeitig verbinden. Beispielsweise nutzen Benutzer aus aller Welt ihre Browser auf ihren Computern, um Taobao.com zu besuchen. Da es sehr praktisch und effizient ist, mehrere Goroutinen in der Go-Sprache zu erstellen, um Parallelität zu erreichen, können wir eine Goroutine erstellen, die jedes Mal verarbeitet wird, wenn eine Verbindung hergestellt wird.

Der Verarbeitungsablauf des TCP-Serverprogramms:

    1.监听端口
    2.接收客户端请求建立链接
    3.创建goroutine处理链接。

Der vom Net-Paket der Go-Sprache implementierte TCP-Servercode lautet wie folgt:

// tcp/server/main.go

// TCP server端

// 处理函数
func process(conn net.Conn) {
    defer conn.Close() // 关闭连接
    for {
        reader := bufio.NewReader(conn)
        var buf [128]byte
        n, err := reader.Read(buf[:]) // 读取数据
        if err != nil {
            fmt.Println("read from client failed, err:", err)
            break
        }
        recvStr := string(buf[:n])
        fmt.Println("收到client端发来的数据:", recvStr)
        conn.Write([]byte(recvStr)) // 发送数据
    }
}

func main() {
    listen, err := net.Listen("tcp", "127.0.0.1:20000")
    if err != nil {
        fmt.Println("listen failed, err:", err)
        return
    }
    for {
        conn, err := listen.Accept() // 建立连接
        if err != nil {
            fmt.Println("accept failed, err:", err)
            continue
        }
        go process(conn) // 启动一个goroutine处理连接
    }
}

Speichern Sie den obigen Code und kompilieren Sie ihn in eine ausführbare Server- oder server.exe-Datei.

TCP-Client

Der Ablauf eines TCP-Clients für die TCP-Kommunikation ist wie folgt:

    1.建立与服务端的链接
    2.进行数据收发
    3.关闭链接

Der mit dem Net-Paket der Go-Sprache implementierte TCP-Client-Code lautet wie folgt:

// tcp/client/main.go

// 客户端
func main() {
    conn, err := net.Dial("tcp", "127.0.0.1:20000")
    if err != nil {
        fmt.Println("err :", err)
        return
    }
    defer conn.Close() // 关闭连接
    inputReader := bufio.NewReader(os.Stdin)
    for {
        input, _ := inputReader.ReadString('\n') // 读取用户输入
        inputInfo := strings.Trim(input, "\r\n")
        if strings.ToUpper(inputInfo) == "Q" { // 如果输入q就退出
            return
        }
        _, err = conn.Write([]byte(inputInfo)) // 发送数据
        if err != nil {
            return
        }
        buf := [512]byte{}
        n, err := conn.Read(buf[:])
        if err != nil {
            fmt.Println("recv failed, err:", err)
            return
        }
        fmt.Println(string(buf[:n]))
    }
}

Kompilieren Sie den obigen Code in die ausführbare Datei client oder client.exe, starten Sie zuerst den Server und dann den Client, geben Sie beliebige Inhalte auf dem Client ein und drücken Sie die Eingabetaste. Sie können die vom Client gesendeten Daten auf dem Server sehen, um sie zu erkennen TCP-Kommunikation.

Vier UDP-Programmierung

Die Go-Sprache implementiert die UDP-Kommunikation

UDP-Protokoll

Der chinesische Name des UDP-Protokolls (User Datagram Protocol) ist User Datagram Protocol. Es handelt sich um ein verbindungsloses Transportschichtprotokoll im OSI-Referenzmodell (Open System Interconnection, Open System Interconnection). Es kann Daten direkt senden und empfangen, ohne eine Verbindung herzustellen Verbindung. Der Empfang ist eine unzuverlässige und nicht in der Reihenfolge liegende Kommunikation, aber das UDP-Protokoll bietet eine bessere Echtzeitleistung und wird normalerweise in Bereichen verwendet, die mit Live-Video zu tun haben.

UDP-Server

Der mit dem Net-Paket der Go-Sprache implementierte UDP-Servercode lautet wie folgt:

// UDP/server/main.go

// UDP server端
func main() {
    listen, err := net.ListenUDP("udp", &net.UDPAddr{
        IP:   net.IPv4(0, 0, 0, 0),
        Port: 30000,
    })
    if err != nil {
        fmt.Println("listen failed, err:", err)
        return
    }
    defer listen.Close()
    for {
        var data [1024]byte
        n, addr, err := listen.ReadFromUDP(data[:]) // 接收数据
        if err != nil {
            fmt.Println("read udp failed, err:", err)
            continue
        }
        fmt.Printf("data:%v addr:%v count:%v\n", string(data[:n]), addr, n)
        _, err = listen.WriteToUDP(data[:n], addr) // 发送数据
        if err != nil {
            fmt.Println("write to udp failed, err:", err)
            continue
        }
    }
}

UDP-Client

Der mit dem Net-Paket der Go-Sprache implementierte UDP-Client-Code lautet wie folgt:

// UDP 客户端
func main() {
    socket, err := net.DialUDP("udp", nil, &net.UDPAddr{
        IP:   net.IPv4(0, 0, 0, 0),
        Port: 30000,
    })
    if err != nil {
        fmt.Println("连接服务端失败,err:", err)
        return
    }
    defer socket.Close()
    sendData := []byte("Hello server")
    _, err = socket.Write(sendData) // 发送数据
    if err != nil {
        fmt.Println("发送数据失败,err:", err)
        return
    }
    data := make([]byte, 4096)
    n, remoteAddr, err := socket.ReadFromUDP(data) // 接收数据
    if err != nil {
        fmt.Println("接收数据失败,err:", err)
        return
    }
    fmt.Printf("recv:%v addr:%v count:%v\n", string(data[:n]), remoteAddr, n)
}

Fünf http-Programmierung

Web-Workflow

Das Funktionsprinzip des Webservers lässt sich einfach wie folgt zusammenfassen:

  • Der Client stellt über das TCP/IP-Protokoll eine TCP-Verbindung zum Server her
  • Der Client sendet ein HTTP-Protokollanforderungspaket an den Server und fordert das Ressourcendokument auf dem Server an
  • Der Server sendet ein HTTP-Protokoll-Antwortpaket an den Client. Wenn die angeforderte Ressource dynamische Sprachinhalte enthält, ruft der Server die Interpretationsmaschine der dynamischen Sprache auf, um den „dynamischen Inhalt“ zu verarbeiten und die verarbeiteten Daten an den Client zurückzugeben.
  • Client vom Server getrennt. Das HTML-Dokument wird vom Client interpretiert und das grafische Ergebnis wird auf dem Client-Bildschirm gerendert

HTTP-Protokoll

Das Hypertext Transfer Protocol (HTTP, HyperText Transfer Protocol) ist das am weitesten verbreitete Netzwerkprotokoll im Internet. Es legt die Regeln für die gegenseitige Kommunikation zwischen Browsern und World Wide Web-Servern fest. Es ist ein Datenübertragungsprotokoll zur Übertragung von World Wide Web-Dokumenten über das Internet
: Wird normalerweise über dem TCP-Protokoll ausgeführt

HTTP-Server

package main

import (
    "fmt"
    "net/http"
)

func main() {
    //http://127.0.0.1:8000/go
    // 单独写回调函数
    http.HandleFunc("/go", myHandler)
    //http.HandleFunc("/ungo",myHandler2 )
    // addr:监听的地址
    // handler:回调函数
    http.ListenAndServe("127.0.0.1:8000", nil)
}

// handler函数
func myHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Println(r.RemoteAddr, "连接成功")
    // 请求方式:GET POST DELETE PUT UPDATE
    fmt.Println("method:", r.Method)
    // /go
    fmt.Println("url:", r.URL.Path)
    fmt.Println("header:", r.Header)
    fmt.Println("body:", r.Body)
    // 回复
    w.Write([]byte("www.5lmh.com"))
}

HTTP-Server

package main

import (
    "fmt"
    "io"
    "net/http"
)

func main() {
    //resp, _ := http.Get("http://www.baidu.com")
    //fmt.Println(resp)
    resp, _ := http.Get("http://127.0.0.1:8000/go")
    defer resp.Body.Close()
    // 200 OK
    fmt.Println(resp.Status)
    fmt.Println(resp.Header)

    buf := make([]byte, 1024)
    for {
        // 接收服务端信息
        n, err := resp.Body.Read(buf)
        if err != nil && err != io.EOF {
            fmt.Println(err)
            return
        } else {
            fmt.Println("读取完毕")
            res := string(buf[:n])
            fmt.Println(res)
            break
        }
    }
}

Sechs WebSocket-Programmierung

Was ist webSocket

  • WebSocket ist ein Protokoll für die Vollduplex-Kommunikation über eine einzelne TCP-Verbindung
  • WebSocket erleichtert den Datenaustausch zwischen Client und Server, indem es dem Server ermöglicht, Daten aktiv an den Client zu übertragen
  • In der WebSocket-API müssen der Browser und der Server nur einen Handshake durchführen, und eine dauerhafte Verbindung kann direkt zwischen den beiden hergestellt und eine bidirektionale Datenübertragung durchgeführt werden.
  • Pakete von Drittanbietern müssen installiert werden:
    In cmd: go get -u -v github.com/gorilla/websocket

Wir starten einen http-Server und geben den Root-Pfad an, um zu einer HTML-Seite weiterzuleiten, die zur Simulation des Clients der WebSocket-Kommunikation verwendet wird. Die Seite bietet eine Schaltfläche zum Auslösen eines JS-Abschnitts, der die WebSocket-Kommunikation ausführt. Der Server empfängt die Websocket-Anfrage und antwortet dem Browser dann vollständig mit dem Inhalt der Anfrage.

Der Server, der die Websocket-Anfrage empfängt:

package main

import (
	"fmt"
	"net/http"

	"github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
}

func main() {
	http.HandleFunc("/echo", func(w http.ResponseWriter, r *http.Request) {
		conn, _ := upgrader.Upgrade(w, r, nil) // error ignored for sake of simplicity

		for {
			// Read message from browser
			msgType, msg, err := conn.ReadMessage()
			if err != nil {
				return
			}

			// Print the message to the console
			fmt.Printf("%s sent: %s\n", conn.RemoteAddr(), string(msg))

			// Write message back to browser
			if err = conn.WriteMessage(msgType, msg); err != nil {
				return
			}
		}
	})

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, "H:\\go\\main\\websockets.html")
	})

	http.ListenAndServe(":8080", nil)
}

Client sendet WebSocket-Anfrage:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WebSockets</title>
</head>
<body>
<input id="input" type="text" />
<button onclick="send()">Send</button>
<pre id="output"></pre>
<script>
    var input = document.getElementById("input");
    var output = document.getElementById("output");
    var socket = new WebSocket("ws://localhost:8080/echo");

    socket.onopen = function () {
        output.innerHTML += "Status: Connected\n";
    };

    socket.onmessage = function (e) {
        output.innerHTML += "Server: " + e.data + "\n";
    };

    function send() {
        socket.send(input.value);
        input.value = "";
    }
</script>
</body>
</html>

Neu gepostet von https://www.cnblogs.com/qi66/p/16773296.html

Supongo que te gusta

Origin blog.csdn.net/lingshengxiyou/article/details/130210580
Recomendado
Clasificación