これまでに学んだことTCP
と UDP
は、まとめて Socker
プログラミングと呼ばれ、別名ソケット プログラミング。
#複数の マシン #相互通信を実現するために ## は、実際には非常に複雑なプロセスです。最下層では、、ネットワーク ケーブルからネットワーク ケーブルを敷設します。インターフェース#,#スイッチ,##ルーター 、Provisionsさまざまなプロトコル。 アプリケーション層に移動 標準のセットがなく、各プログラマがそれを使用するたびに自分で実装しなければならない場合、髪を失うほど簡単ではないかもしれません。 サッカーをした後 TCP は安定した信頼性の高い長い接続です。 通信が関係するため、2 つの端末が必要です。少なくとも 1 つは サーバー で、もう 1 つは # です。 ##クライアント, タオバオと同じように、タオバオを開くたびにタオバオにリンクする必要があります。もちろん、タオバオは直接 TCP## ではありません コードQQ
、WeChat
、などのソフトウェア。 ソッカー
, Socker
は、アプリケーション層の前にさまざまな面倒な基礎操作を非表示にします。必要なのは、Socker.TCP
だけです。 TCP
プロトコルの通信。 Go languageTCP
#。
Go でサーバーを実装すると、サーバーでの同時実行が非常に簡単になり、接続ごとに 1 つのプロトコルを許可するだけで済みます。 . 加工するだけ!
package main
import (
"bufio"
"fmt"
"net"
)
func process(conn net.Conn) {
defer conn.Close()
for {
reader := bufio.NewReader(conn)
buf := make([]byte, 128)
n, err := reader.Read(buf)
if err != nil {
fmt.Println("数据读取失败", err)
return
}
recvStr := string(buf[:n])
fmt.Println("客户端发送过来的值:", recvStr)
}
}
func main() {
lister, err := net.Listen("tcp", "0.0.0.0:8008")
if err != nil {
fmt.Println("连接失败", err)
}
for {
fmt.Println("等待建立连接,此时会阻塞住")
conn, err := lister.Accept() //等待建立连接
fmt.Println("连接建立成功,继续")
if err != nil {
fmt.Println("建立连接失败", err)
//继续监听下次链接
continue
}
go process(conn)
}
}
代码 就这样,我们实现了服务端并发的处理所有客户端的请求。 我们先看一下什么是粘包。 注意:18行代码睡眠了1s #コードの 18 行目をコメントすると ##すべて 1 行にまとめられていますが、何ですか?何が起こっているのでしょうか? 以前と同じではないでしょうか? ? ? 値が送信されるたびに、それは向こうで受信されます。なぜこれがすべて 1 つのまとまりになっているのでしょうか。 ! ! #理由 ソフトウェアは、 オペレーティング システム 上で実行されるソフトウェアです。サーバーにデータを送信するときのデータは、## です。 # オペレーティング システム の 関連インターフェイス を呼び出して送信すると、オペレーティング システムはさまざまな複雑な操作を経て、 ただし、オペレーティング システムにはデータ送信用のバッファがあります。デフォルトでは、バッファにサイズがあり、バッファがいっぱいでない場合、データは送信されません送信する必要があるため、上記のクライアントは、データを送信する際、システムのバッファがいっぱいではなく、オペレーティング システムのバッファに保持されていましたが、最終的にデータが存在しないことが判明したため、サーバーに一括送信されました しかし、なぜ カプセル化を解決します。カプセル化パッケージの関数 这次真的不管执行几次,都是这样的结果 对了,只有 例如直播行业package main
import (
"bufio"
"fmt"
"net"
"os"
)
//客户端
func main() {
conn, err := net.Dial("tcp", "192.168.10.148:8008")
if err != nil {
fmt.Println("连接服务器失败",err)
}
defer conn.Close()
inputReader:=bufio.NewReader(os.Stdin)
for{
fmt.Println(":")
input,_:=inputReader.ReadString('\n')
_, err = conn.Write([]byte(input))
if err != nil {
fmt.Println("发送成功")
}
}
}
执行结果
粘包
服务端
package main
import (
"bufio"
"fmt"
"io"
"net"
)
func process(conn net.Conn) {
defer conn.Close()
reader := bufio.NewReader(conn)
buf := make([]byte, 1024)
for {
n, err := reader.Read(buf)
//读完了
if err == io.EOF {
fmt.Println("读完了")
break
}
//读错了
if err != nil {
fmt.Println("数据读取失败", err)
return
}
recvStr := string(buf[:n])
fmt.Println("客户端发送过来的值:", recvStr)
}
}
func main() {
lister, err := net.Listen("tcp", "0.0.0.0:8008")
if err != nil {
fmt.Println("连接失败", err)
return
}
defer lister.Close()
for {
fmt.Println("等待建立连接,此时会阻塞住")
conn, err := lister.Accept() //等待建立连接
fmt.Println("连接建立成功,继续")
if err != nil {
fmt.Println("建立连接失败", err)
//继续监听下次链接
continue
}
go process(conn)
}
}
客户端
package main
import (
"fmt"
"net"
)
//客户端
func main() {
conn, err := net.Dial("tcp", "192.168.10.148:8008")
if err != nil {
fmt.Println("连接服务器失败", err)
}
defer conn.Close()
for i := 0; i < 10; i++ {
sendStr := "hello world ads asdf asd fads fadsf ads ads asd asd ads "
conn.Write([]byte(sendStr))
time.Sleep(time.Second)
}
}
执行结果
主な理由は、#アプリケーション層であるためです
sleep(1)
は再び機能するのでしょうか? これは、バッファーが複数のプログラムによって使用されており、1 秒が十分です 他のプログラムがバッファをいっぱいにして、独自のデータを送信します。これが、最初の操作は問題ありませんが、2 回目の操作は問題がある理由です。2 回目はクライアントによってすべて埋められるためです。スティッキーなパッケージの解決策
ツール機能
socker_sitck/stick.go
package socker_stick
import (
"bufio"
"bytes"
"encoding/binary"
"fmt"
)
//Encode 将消息编码
func Encode(message string) ([]byte, error) {
length := int32(len(message))
var pkg = new(bytes.Buffer)
//写入消息头
err := binary.Write(pkg, binary.LittleEndian, length)
if err != nil {
fmt.Println("写入消息头失败", err)
return nil, err
}
//写入消息实体
err = binary.Write(pkg, binary.LittleEndian, []byte(message))
if err != nil {
fmt.Println("写入消息实体失败", err)
return nil, err
}
return pkg.Bytes(), nil
}
//Decode解码消息
func Decode(reader *bufio.Reader) (string, error) {
//读取信息长度
lengthByte, _ := reader.Peek(4)
lengthBuff := bytes.NewBuffer(lengthByte)
var length int32
err := binary.Read(lengthBuff, binary.LittleEndian, &length)
if err != nil {
return "", err
}
//BuffRead 返回缓冲区现有的可读的字节数
if int32(reader.Buffered()) < length+4 {
return "", err
}
pack := make([]byte, int(4+length))
_, err = reader.Read(pack)
if err != nil {
return "", err
}
return string(pack[4:]), nil
}
服务端
package main
import (
"a3_course/socker_stick"
"bufio"
"fmt"
"io"
"net"
)
func process(conn net.Conn) {
defer conn.Close()
reader := bufio.NewReader(conn)
for {
msg, err := socker_stick.Decode(reader)
//读完了
if err == io.EOF {
fmt.Println("读完了")
break
}
//读错了
if err != nil {
fmt.Println("数据读取失败", err)
return
}
fmt.Println("客户端发送过来的值:", msg)
}
}
func main() {
lister, err := net.Listen("tcp", "0.0.0.0:8008")
if err != nil {
fmt.Println("连接失败", err)
return
}
defer lister.Close()
for {
fmt.Println("等待建立连接,此时会阻塞住")
conn, err := lister.Accept() //等待建立连接
fmt.Println("连接建立成功,继续")
if err != nil {
fmt.Println("建立连接失败", err)
//继续监听下次链接
continue
}
go process(conn)
}
}
客户端
package main
import (
"a3_course/socker_stick"
"fmt"
"net"
)
//客户端
func main() {
conn, err := net.Dial("tcp", "192.168.10.148:8008")
if err != nil {
fmt.Println("连接服务器失败", err)
}
defer conn.Close()
for i := 0; i < 10; i++ {
sendStr := "hello world ads asdf asd fads fadsf ads ads asd asd ads "
data, err := socker_stick.Encode(sendStr)
if err != nil {
fmt.Println("编码失败",err)
return
}
conn.Write(data)
//time.Sleep(time.Second)
}
}
执行结果
TCP
才有粘包Go语言UDP
UDP
是一个无连接协议,客户端不会在乎服务端有没有问题,客户端只管发,通常用于实时性比较高的领域服务端
package main
import (
"fmt"
"net"
)
func main() {
listen, err := net.ListenUDP("udp", &net.UDPAddr{
IP: net.IPv4(0, 0, 0, 0),
Port: 8009,
})
if err != nil {
panic(fmt.Sprintf("udp启动失败,err:%v", err))
}
defer listen.Close()
for{
var data = make([]byte,1024)
n, addr, err := listen.ReadFromUDP(data)
if err != nil {
panic(fmt.Sprintf("读取数据失败,err:%v", err))
}
fmt.Println(string(data[:n]),addr,n)
}
}
客户端
package main
import (
"fmt"
"net"
)
func main() {
socker, err := net.DialUDP("udp", nil, &net.UDPAddr{
IP: net.IPv4(0, 0, 0, 0),
Port: 8009,
})
if err != nil {
panic(fmt.Sprintf("连接服务器失败,err:%v", err))
}
defer socker.Close()
sendStr:="你好呀"
_, err = socker.Write([]byte(sendStr))
if err != nil {
panic(fmt.Sprintf("数据发送失败,err:%v", err))
}
}
本次章节我们讲述了什么是TCP,什么是UDP。
并且编写了代码如何实现TCP服务端,TCP客户端,UDP服务端,UDP客户端。
讲述了为什么会出现粘包,该怎么解决粘包。
以上がGo 言語ネットワーク プログラミングの基本を理解するのに役立つ記事の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。