TCP UDP done
parent
05e21d15c5
commit
a5b20d8c4b
|
@ -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}
|
|
@ -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
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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]))
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue