我们所学的TCP
TCP
和UDP
,统称为Socker
和UDP
,统称为 socker
编程, 也 叫做
套 接字 编程 。多台机器要实现互相通讯,其实是一一不层从铺设网线,网线接口, 交换机,路由器,在到规定
🎜🎜各种协🎜🎜🎜🎜🎜🎜Pergi ke lapisan aplikasiQQ
QQ
,微信
等软件。
如果没有一套标准,每次使用都要自己去实现,可能每个程序员都不是掉头发那么简单了!
有了Socker
之后,Socker
会在应用层之前,将各种繁琐的的底层操作隐藏,我们可能只需要Socker.TCP
就实现了TCP
, WeChat
🎜if Tiada satu set piawaian Anda perlu melaksanakannya sendiri setiap kali anda menggunakannya Mungkin setiap pengaturcara tidak semudah kehilangan rambutnya! 🎜🎜
🎜 p cid="n12" mdtype="paragraph" style="max-width:90%"Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size: 16px;text-align: start;">🎜 Faham🎜🎜 Socker
Selepas 🎜🎜, 🎜🎜Socker
🎜🎜 akan menyembunyikan pelbagai operasi asas yang membosankan sebelum lapisan aplikasi Kita mungkin hanya memerlukan 🎜🎜Socker.TCP
🎜🎜 dicapai🎜🎜TCP
🎜🎜 komunikasi protokol. 🎜🎜🎜
TCP ialah sambungan panjang yang stabil dan boleh dipercayai
Memandangkan komunikasi terlibat, mesti ada dua terminal, sekurang-kurangnya satu adalah . satu adalah pelanggan , sama seperti Taobao kami Setiap kali kami membuka Taobao, kami mesti memautkannya secara langsung . TCP
Pelayan
Kod
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)
}
}
代码
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) } }
注意:18行代码睡眠了1s
Jika saya mengulas baris ke-18 kod
, apakah yang ditambah secara langsung pada satu baris? Apa yang berlaku? ? ?
Setiap kali nilai dihantar, ia diterima di sana Bagaimana ini boleh disepadukan menjadi satu bahagian? ! !
Sebab utamanya ialah kerana kita lapisan aplikasiperisian, iaitu perisian yang berjalan pada sistem pengendalian kami pelayan, Ia dihantar dengan memanggil antara muka yang berkaitan sistem pengendalian Sistem pengendalian kemudiannya melalui pelbagai operasi yang kompleks dan menghantarnya ke mesin yang lain
. sistem pengendalian mempunyai penimbal data penghantaran Secara lalai, jika penimbal mempunyai saiz tertentu, data tidak akan dihantar jika penimbal tidak penuh Oleh itu, apabila pelanggan di atas menghantar data, penimbal sistem tidak penuh, dan ia sentiasa ditekan dalam penimbal sistem operasi , akhirnya mendapati tiada data, jadi ia dihantar ke pelayan sekaligusTetapi kenapa 我们将解包封包的函数封装一下 🎜Kami akan merangkum fungsi membongkar paket🎜🎜< p cid="n50" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;anak yatim: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;font- family: 'Open Sans', 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size: 16px;text-align: start;">🎜 这次真的不管执行几次,都是这样的结果 对了,只有 例如直播行业 本次章节我们讲述了什么是TCP,什么是UDP。 并且编写了代码如何实现TCP服务端,TCP客户端,UDP服务端,UDP客户端。 讲述了为什么会出现粘包,该怎么解决粘包。sleep(1)
sleep(1)
又管用了呢?这是因为缓冲区不止一个程序在用,1s的时间足够其他程序将缓冲区打满,然后各自发各自的数据,这也是为什么第一次操作没问题,第二次有问题,因为第二次全部都是我们客户端打满的解决粘包
工具函数
socker_sitck/stick.go
Ia berfungsi semula? Ini kerana buffer digunakan oleh lebih daripada satu program 1s adalah masa yang cukup untuk program lain untuk mengisi buffer dan kemudian menghantar data mereka sendiri pertama Tiada masalah dengan operasi pertama, tetapi terdapat masalah kali kedua, kerana kali kedua semuanya dimuatkan sepenuhnya pada klien kami🎜 Selesaikan beg melekit🎜
🎜Fungsi alat🎜
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))
}
}
执行结果
总结
Atas ialah kandungan terperinci Artikel untuk membantu anda memahami asas pengaturcaraan rangkaian bahasa Go. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!