三次握手
主动发起请求端,发送SYN(SYN表示建立连接)
被动建立连接请求端,会去应答ACK同时发送SYN
主动发起请求端,发送应答ACK (ACK表示响应)
四次挥手
1主动关闭连接请求端,发送FIN (FIN表示关闭连接)
2被动关闭连接请求端,应答ACK 半关闭完成
3被动关闭连接请求端,发送FIN
4主动关闭连接请求端,应答ACK
因为有半关闭状态,所以会多发一次请求,先由客户端发送请求告诉服务端要关闭连接了,服务端回信告诉客户端可以关闭,然后这里处于半关闭状态,因为服务端还可以往外发,服务端这时候发送关闭请求给客户端,客户端响应,这时候才真正的关闭了连接
当客户端点击断开连接后服务端就会收到一个空包,所以可以通过判断接受到的数据是否为空来判断客户端是否断开链接**
for {
n, err := conn.Read(buf)
if n == 0 { //通过判断读到的内容长度来判断客户端是否已经关闭连接
fmt.Println("服务器监测到客户端已关闭")
}
if err != nil {
return
}
fmt.Println("服务器读到数据", string(buf[:n]))
conn.Write([]byte(strings.ToUpper(string(buf[:n]))))
}
osi模型 物 数 网 传 会 表 应
tcpip模型 数 网 传 应
链路层:网卡和网卡通信需要mac地址,发送arp包到路由器,路由器广播,目标网卡检查ip和arp包中ip一样后,会把自己的mac地址加入arp包中再发回给路由器再广播 arp协议 借助ip获取mac地址,用来寻找另外一台主机的mac地址。设备到设备 rarp是倒过来
网络层: ip协议,在网络中确定一台主机。主机到主机
传输层:tcp udp协议,主要目的是为了封装端口号 port,在主机中找进程。
应用层:FTp http用户自定义的,和具体应用有关
并发cs server
package main
import (
"fmt"
"net"
"strings"
)
func handlerConnect(conn net.Conn) {
defer conn.Close()
//获取链接的客户端
addr := conn.RemoteAddr()
fmt.Println("客户端链接成功", addr)
//循环读取客户端发送数据
buf := make([]byte, 1024)
for {
n, err := conn.Read(buf)
if n == 0 {
fmt.Println("服务器监测到客户端已关闭")
}
if err != nil {
return
}
fmt.Println("服务器读到数据", string(buf[:n]))
conn.Write([]byte(strings.ToUpper(string(buf[:n]))))
}
}
func main() {
listener, err := net.Listen("tcp", "127.0.0.1:8001")
if err != nil {
return
}
defer listener.Close()
for {
conn, err := listener.Accept()
if err != nil {
return
}
go handlerConnect(conn)
}
}
并发cs client
package main
import (
"fmt"
"net"
"os"
)
func main() {
conn, err := net.Dial("tcp", "127.0.0.1:8001")
if err != nil {
fmt.Println("net.Dial err:", err)
return
}
defer conn.Close()
go func() {
str := make([]byte, 4096)
for {
n, err := os.Stdin.Read(str)
if err != nil {
continue
}
conn.Write(str[:n])
}
}()
for {
str := make([]byte, 4096)
n, err := conn.Read(str)
if n == 0 {
fmt.Println("检测到服务器关闭")
return
}
if err != nil {
return
}
fmt.Println(string(str[:n]))
}
}