Go-网络编程(TCP)

Go中提供了网络编程接口支持HTTP、TCP、UDP协议等,下面演示下TCP通信Server、Client

Server

package main

import (
    "fmt"
    "net"
)

func main() {
    // 创建一个 TCP 监听器
    listener, err := net.Listen("tcp", "127.0.0.1:9000")
    if err != nil {
        fmt.Println("Error:", err)
        return
    }

    fmt.Println("Server listening on port 9000")

    // 循环监听客户端连接请求
    for {
        conn, err := listener.Accept()
        if err != nil {
            fmt.Println("Error:", err)
            continue
        }

        // 处理客户端连接请求
        go handleConnection(conn)
    }
}

func handleConnection(conn net.Conn) {
    defer conn.Close()

    // 读取客户端发送的数据
    buf := make([]byte, 1024)
    n, err := conn.Read(buf)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }

    // 处理客户端发送的数据
    data := buf[:n]
    fmt.Println("Received data: ", string(data))

    // 发送响应数据给客户端
    response := "Hello, client! 我是Server,Over"
    conn.Write([]byte(response))
}

Client

package main

import (
    "fmt"
    "net"
)

func main() {
    // 连接服务器
    conn, err := net.Dial("tcp", "127.0.0.1:9000")
    if err != nil {
        fmt.Println("Error:", err)
        return
    }

    // 发送数据给服务器
    message := "Hello, server! 我是Client"
    conn.Write([]byte(message))

    // 读取服务器响应数据
    buf := make([]byte, 1024)
    n, err := conn.Read(buf)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }

    // 处理服务器响应数据
    data := buf[:n]
    fmt.Println("Received data: ", string(data))

    conn.Close()
}

运行

  • 客户端不断发送请求
  • 服务端读取请求
  • 服务端处理请求
  • 服务端写回响应

Server run

Client run

Client发起请求,收到Server的相应

Wireshark分析

使用Wireshark工具分析下请求响应的流程

tcp.port == 9000 and ip.addr == 127.0.0.1

 上图是这是Server、Client之间的本地回环通信(Loopback),源和目标IP地址均为127.0.0.1,因此这些包不会离开本地主机。下面是每个TCP报文段的解释:

  • 10252:系统为Client动态随机分配的端口
  • 9000:Server的端口
  • 第339号数据包:Client向Server发送SYN请求连接,seq=0,win=65535,mss=65495,ws=256,sack_perm,表示客户端请求建立连接,并发送了自己的窗口大小、最大分段大小、窗口扩展、SACK_PERM等信息给Server。

  • 第340号数据包:Server响应Client的SYN请求,ack=1,win=65535,mss=65495,ws=256,sack_perm,表示服务端接收到了客户端的请求,并发送了自己的窗口大小、最大分段大小、窗口扩展、SACK_PERM等信息给Client。

  • 第341号数据包:Client确认Server的SYN,ACK响应,seq=1,ack=1,win=2161152,表示客户端接收到了服务端的响应,并发送了自己的序列号、确认号和窗口大小给Server。

  • 第342号数据包:Client向Server发送数据,seq=1,ack=1,win=2161152,len=27,表示客户端向服务端发送了长度为27的数据,并发送了自己的序列号、确认号和窗口大小给Server。

  • 第343号数据包:Server对Client发送的数据进行确认,seq=1,ack=28,win=2161152,表示服务端接收到了客户端发送的数据,并发送了自己的确认号和窗口大小给Client。

  • 第344号数据包:Server向Client发送数据,seq=1,ack=28,win=2161152,len=32,表示服务端向客户端发送了长度为32的数据,并发送了自己的序列号、确认号和窗口大小给Client。

  • 第345号数据包:Client对Server发送的数据进行确认,seq=28,ack=33,win=2161152,表示客户端接收到了服务端发送的数据,并发送了自己的确认号和窗口大小给Server。

  • 第346号数据包:Server向Client发送FIN,ACK关闭连接,seq=33,ack=28,win=2161152,len=0,表示服务端发送了FIN和ACK标志位,表示将关闭连接,并发送了自己的序列号、确认号和窗口大小给Client。

  • 第347号数据包:Client对Server的FIN,ACK响应进行确认,seq=28,ack=34,win=2161152,表示客户端接收到了服务端的FIN和ACK标志位,并发送了自己的确认号和窗口大小给Server。

  • 第348号数据包:Client向Server发送FIN,ACK关闭连接,seq=28,ack=34,win=2161152,len=0,表示客户端发送了FIN和ACK标志位,表示将关闭连接,并发送了自己的序列号、确认号和窗口大小给Server。

  • 第349号数据包:Server对Client的FIN,ACK响应进行确认,seq=34,ack=29,win=2161152,表示服务端接收到了客户端发送的FIN和ACK标志位,并发送了自己的确认号和窗口大小给Client。

参数解释:

  • seq:序列号,用于标识每个TCP报文段中的数据字节流,是发送方维护的一个32位无符号整数,用于保证TCP数据可靠传输,表示本报文段中首个数据字节的序号。

  • ack:确认号,用于对序列号的确认,是对方期望接收到的下一个TCP报文段的第一个字节的序号,也是本报文段中确认的数据字节序号。

  • win:窗口大小,表示接收方还能够接收多少字节的数据,是接收方用于控制发送方发送速度的一个参数,由接收方通过ACK报文向发送方通知。

  • mss:最大分段大小,是指TCP报文段中的数据部分的最大长度,是发送方和接收方通过协商确定的,一般是两端协商后支持的最大MTU减去TCP报头的长度。

  • ws:窗口扩展,是TCP连接中的一种可选参数,表示TCP窗口大小的扩展,用于提高传输效率,可选参数值为0-14,表示窗口大小扩展的因子。

  • sack_perm:是TCP连接中的一种可选参数,表示是否启用SACK(Selective Acknowledgment,选择性确认)选项,如果启用,则可以提高TCP数据传输的可靠性和效率,但会增加数据包大小。

  • len:数据长度,是指TCP报文段中数据部分的长度,不包括TCP报头和选项部分的长度。


 

在TCP通信中,常见的标志位有以下几个:

  • SYN:同步序列号,用于建立一个新的TCP连接。
  • ACK:确认序号,用于确认收到的数据。
  • PSH:推送数据,用于传输数据前通知对方尽快处理。
  • FIN:结束通信,用于终止一个TCP连接。

具体来说:

  • SYN:SYN标志用于建立一个新的TCP连接。TCP协议使用“三次握手”来确保连接的可靠性,其中SYN标志用于表示客户端请求连接,服务端在收到请求后会发送SYN+ACK标志,用于表示接收请求并确认连接。客户端再发送一次ACK标志,用于确认服务端的SYN+ACK。这个过程中,客户端和服务端的序列号都会发送一些初始值。
  • ACK:ACK标志主要用于确认收到的数据。在TCP通信中,接收方一般会返回一个ACK标志,用于告诉对方收到了数据。ACK标志也可以用于确认已经成功建立了一个TCP连接。
  • PSH:PSH标志用于通知接收方立即处理数据,不进行数据缓存。在传输一些实时性要求高的数据时,可以使用PSH标志来加快数据的传输速度。
  • FIN:FIN标志用于结束一个TCP连接。TCP通信中的连接是双向传输的,因此FIN标志可以由客户端或服务端发起,用于终止连接。当一方发送了FIN标志之后,另一方会发送一个ACK标志,然后也发送一个FIN标志,最终关闭连接。
posted @ 2023-04-03 15:20  GJH-  阅读(26)  评论(0编辑  收藏  举报