package main
import (
"fmt"
"net"
)
func main() {
//1、监听端口
listener, err := net.Listen("tcp", "0.0.0.0:9090")
if err != nil {
fmt.Printf("listen fail, err: %v\n", err)
return
}
//2.建立套接字连接
for {
conn, err := listener.Accept()
if err != nil {
fmt.Printf("accept fail, err: %v\n", err)
continue
}
//3. 创建处理协程
go func(conn net.Conn) {
//defer conn.Close() //思考题:这里不填写会有啥问题?
// 这里不关闭的话 服务端出现close_wait 客户端fin_wait
for {
var buf [128]byte
n, err := conn.Read(buf[:])
if err != nil {
fmt.Printf("read from connect failed, err: %v\n", err)
break
}
str := string(buf[:n])
fmt.Printf("receive from client, data: %v\n", str)
}
}(conn)
}
}
TCP为啥需要流量控制
由于通讯双方,网速不同。通讯方任一方发送的过快都会导致对方消息处理不过来,所以就需要把数据放到缓冲区中如果缓冲区满了,发送方还在疯狂发送,那么接收方只能把数据包丢弃。因此我们需要控制发送速率我们缓冲区剩余大小称之为接收窗口,用变量win表示、如果wiin=0.则发送方停止发送TCP为啥需要拥塞控制 流量控制和拥塞控制是两个概念,拥塞控制是调解网络的负载接收方网络资源繁忙,因未及时响应ACK导致发送方重传大量数据,这样将会导致网络更加拥堵拥堵控制是动态调整win大小,不只是依赖缓冲区大小确认窗口大小 TCP拥塞控制 慢开始和拥塞避免快速重传和快速恢复
为什么会出现粘包和拆包 应用程序写入的数据大于套接字缓冲区大小,这将会发生拆包应用程序写入数据小于套接字缓冲=区大小,网卡将应用多次写入的数据发送到网络上,这将会发生粘包进行MSS(最大报文长度)大小的TCP分段,当TCP报文长度-TCP头部长度>MSS的时候将发送拆包接收方法不及时读取套接字缓冲区数据,这将会发生粘包
一个简单的decode和encode代码
package main
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
)
const Msg_Header = "12345678"
func main() {
//类比接收缓冲区 net.Conn
bytesBuffer := bytes.NewBuffer([]byte{})
//发送
if err := Encode(bytesBuffer, "hello world 0!!!"); err != nil {
panic(err)
}
if err := Encode(bytesBuffer, "hello world 1!!!"); err != nil {
panic(err)
}
//读取
for {
if bt, err := Decode(bytesBuffer); err == nil {
fmt.Println(string(bt))
continue
}
break
}
}
func Encode(bytesBuffer io.Writer, content string) error {
//msg_header+content_len+content
//8 +4 +content
if err := binary.Write(bytesBuffer, binary.BigEndian, []byte(Msg_Header)); err != nil {
return err
}
clen := int32(len([]byte(content)))
if err := binary.Write(bytesBuffer, binary.BigEndian, clen); err != nil {
return err
}
if err := binary.Write(bytesBuffer, binary.BigEndian, []byte(content)); err != nil {
return err
}
return nil
}
func Decode(bytesBuffer io.Reader) (bodyBuf []byte, err error) {
MagicBuf := make([]byte, len(Msg_Header))
if _, err = io.ReadFull(bytesBuffer, MagicBuf); err != nil {
return nil, err
}
if string(MagicBuf) != Msg_Header {
return nil, errors.New("msg_header error")
}
lengthBuf := make([]byte, 4)
if _, err = io.ReadFull(bytesBuffer, lengthBuf); err != nil {
return nil, err
}
length := binary.BigEndian.Uint32(lengthBuf)
bodyBuf = make([]byte, length)
if _, err = io.ReadFull(bytesBuffer, bodyBuf); err != nil {
return nil, err
}
return bodyBuf, err
}
服务端和客户端代码
package main
import (
"fmt"
"github.com/e421083458/gateway_demo/demo/base/unpack/unpack"
"net"
)
func main() {
//simple tcp server
//1.监听端口
listener, err := net.Listen("tcp", "0.0.0.0:9090")
if err != nil {
fmt.Printf("listen fail, err: %v\n", err)
return
}
//2.接收请求
for {
conn, err := listener.Accept()
if err != nil {
fmt.Printf("accept fail, err: %v\n", err)
continue
}
//3.创建协程
go process(conn)
}
}
func process(conn net.Conn) {
defer conn.Close()
for {
bt, err := unpack.Decode(conn)
if err != nil {
fmt.Printf("read from connect failed, err: %v\n", err)
break
}
str := string(bt)
fmt.Printf("receive from client, data: %v\n", str)
}
}
package main
import (
"fmt"
"github.com/e421083458/gateway_demo/demo/base/unpack/unpack"
"net"
)
func main() {
conn, err := net.Dial("tcp", "localhost:9090")
defer conn.Close()
if err != nil {
fmt.Printf("connect failed, err : %v\n", err.Error())
return
}
unpack.Encode(conn, "hello world 0!!!")
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)