TCP UDP done

main
Your Name 2024-07-10 19:46:50 +08:00
parent 05e21d15c5
commit a5b20d8c4b
8 changed files with 214 additions and 1 deletions

View File

@ -17,3 +17,20 @@ IPv4这个版本规定网络地址由32个二进制位组成我们通常
也就是说,我们还需要一个参数,表示这个数据包到底供哪个程序(进程)使用。这个参数就叫做"端口”port它其实是每一个使用网卡的程序的编号。
每个数据包都发到主机的特定端口,所以不同的程序就能取到自己所需要的数据。
“端口"是0到65535之间的一个整数正好16个二进制位。0到1023的端口被系统占用用户只能选用大于1023的端口。有了IP和端口我们就能实现唯一确定互联网上一个程序进而实现网络间的程序通信。
TCP服务端程序的处理流程
1.监听端口
2.接收客户端请求建立链接
3.创建goroutine处理链接。
一个TCP客户端进行TCP通信的流程如下
1.建立与服务端的链接
2.进行数据收发
3.关闭链接
TCP粘包
引申知识点:
大端和小端{https://zhuanlan.zhihu.com/p/680366680}

View File

@ -12,10 +12,11 @@ import (
//TCP server端
func process(conn net.Conn) {
defer conn.Close()
var tmp = make([]byte, 1024)
reader := bufio.NewReader(os.Stdin)
for {
n, err := conn.Read(tmp[:])
n, err := conn.Read(tmp)
if err != nil {
log.Fatal("read failed on:", err)
return

View File

@ -0,0 +1,28 @@
package main
import (
"fmt"
"net"
"course/networkProgram/protocol"
)
// socket_stick/client/main.go
func main() {
conn, err := net.Dial("tcp", "127.0.0.1:30000")
if err != nil {
fmt.Println("dial failed, err", err)
return
}
defer conn.Close()
for i := 0; i < 20; i++ {
msg := `Hello, Hello. How are you?`
b, err := proto.Encode(msg)
if err != nil {
fmt.Println("encode failed, err", err)
}
conn.Write(b)
//time.Sleep(1 * time.Second)
}
}

View File

@ -0,0 +1,44 @@
package main
import (
"bufio"
proto "course/networkProgram/protocol"
"fmt"
"io"
"net"
)
// socket_stick/server/main.go
func proc(conn net.Conn) {
defer conn.Close()
reader := bufio.NewReader(conn)
for {
msg, err := proto.Decode(reader)
if err == io.EOF {
return
}
if err != nil {
fmt.Println("decode msg failed, err:", err)
return
}
fmt.Println("收到client发来的数据", msg)
}
}
func main() {
listen, err := net.Listen("tcp", "127.0.0.1:30000")
if err != nil {
fmt.Println("listen failed, err:", err)
return
}
defer listen.Close()
for {
conn, err := listen.Accept()
if err != nil {
fmt.Println("accept failed, err:", err)
continue
}
go proc(conn)
}
}

View File

@ -0,0 +1,39 @@
package main
import (
"bufio"
"fmt"
"log"
"net"
"os"
)
//UDP client
func main() {
socket, err := net.DialUDP("udp", nil, &net.UDPAddr{
IP: net.IPv4(127, 0, 0, 1),
Port: 40000,
})
if err != nil {
log.Fatal("连接服务端失败err", err)
return
}
defer socket.Close()
reader := bufio.NewReader(os.Stdin)
reply := make([]byte, 512)
for {
fmt.Print("> ")
msg, _ := reader.ReadString('\n')
socket.Write([]byte(msg))
//收回复的数据
n, _, err := socket.ReadFromUDP(reply)
if err != nil {
fmt.Println("read reply msg failed:", err)
return
}
fmt.Print(string(reply[:n]))
}
}

View File

@ -0,0 +1,34 @@
package main
import (
"fmt"
"log"
"net"
"strings"
)
// UDP sever
func main() {
conn, err := net.ListenUDP("udp", &net.UDPAddr{
IP: net.IPv4(127, 0, 0, 1),
Port: 40000,
})
if err != nil {
log.Fatal("listen udp failed:", err)
return
}
defer conn.Close()
//不需要建立链接,直接收发数据
data := make([]byte, 1024)
for {
n, addr, err := conn.ReadFromUDP(data)
if err != nil {
log.Println("read from udp failed:", err)
}
fmt.Printf("%s\n", data[:n])
reply := string(data[:n])
reply = strings.ToUpper(reply)
//发送数据
conn.WriteToUDP([]byte(reply), addr)
}
}

View File

@ -0,0 +1,50 @@
// socket_stick/proto/proto.go
package proto
import (
"bufio"
"bytes"
"encoding/binary"
)
// Encode 将消息编码
func Encode(message string) ([]byte, error) {
// 读取消息的长度转换成int32类型占4个字节
var length = int32(len(message))
var pkg = new(bytes.Buffer)
// 写入消息头
err := binary.Write(pkg, binary.LittleEndian, length)
if err != nil {
return nil, err
}
// 写入消息实体
err = binary.Write(pkg, binary.LittleEndian, []byte(message))
if err != nil {
return nil, err
}
return pkg.Bytes(), nil
}
// Decode 解码消息
func Decode(reader *bufio.Reader) (string, error) {
// 读取消息的长度
lengthByte, _ := reader.Peek(4) // 读取前4个字节的数据
lengthBuff := bytes.NewBuffer(lengthByte)
var length int32
err := binary.Read(lengthBuff, binary.LittleEndian, &length)
if err != nil {
return "", err
}
// Buffered返回缓冲中现有的可读取的字节数。
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
}