Socket TCP 使用入门

Socket TCP 使用入门

TCP 通信协议

  • 网络通信的状态

    • LISTENING - 表示正在监听传入连接的端口。
    • ESTABLISHED - 表示已经建立连接的正常数据传输状态。
    • CLOSE_WAIT - 表示本地已经完成数据传输,正在等待关闭连接。
    • TIME_WAIT - 表示连接已经关闭,但是仍在等待一段时间以确保所有传输的数据都被清理和确认。
    • SYN_SENT - 表示正在尝试建立传出连接的初始状态,等待对方确认。
    • SYN_RECEIVED - 表示收到对方的连接请求(SYN)并发送了确认请求(ACK)。
    • FIN_WAIT_1 - 表示已经发送了连接关闭请求(FIN)并等待对方确认。
    • FIN_WAIT_2 - 表示已接收到对方的关闭请求(FIN)并发送了确认(ACK)。
    • CLOSING - 表示在关闭连接期间遇到了问题或发生了错误。
    • LAST_ACK - 表示已发送连接关闭请求(FIN)并收到了对方的确认(ACK),等待最后的关闭确认。
    • CLOSED - 表示连接已经完全关闭或未打开。
      可使用命令 netstat -nao 命令查看计算机进程映射的端口
  • 三次握手

    • 第一次
      客户端发送一个 SYN 包给服务端
    • 第二次
      服务端接收到数据后,返回一个 SYN-ACK 包给客户端
    • 第三次
      客户端接收到数据后,返回一个 ACK 包给服务端

客户端 服务器
init -> SYN listen 客户端发送一个请求连接的 syn 包 1次
syn-send SYN+ACK <- listen 服务端返回一个 syn+ack 包 2次
syn-send -> ACK syn-rcvd 客户端返回一个 ack 包 3次

为什么是三次而不是两次?
服务端回复 syn+ack 后就建立连接,防止已经失效的请求报文突然又传到服务器引起错误。
例如:客户端发送 syn 包产生滞留情况。

  • 四次挥手
    • 第一次
      客户端发送 FIN 包给服务端
    • 第二次
      服务端接收到数据后,返回 ACK 包给客户端
    • 第三次
      服务端发送 FIN 包给客户端
    • 第四次
      客户端接收到数据后,返回 ACK 包给服务端

客户端 服务器
established -> FIN established 客户端发送 final 包 1次
fin-wait-1 ACK <- Close-Wait 服务端返回 ack 包 2次

此时服务端还可发送未发送的数据,客户端也还可以接收数据。
fin-wait-2 FIN <- Close-Wait 服务端发送一个 fin 包 3次
fin-wait-2 -> ACK Last-Ack 4次

客户端发送 ack 后进入超时等待状态 ,而服务端接收到 ack 包后立刻关闭。
time-wait Closed
Closed

为什么4次挥手后要进入超时等待?
客户端发送 ack 包之后,如果服务端没有接收到 ack, 那么服务端会再发送 fin 包,客户端接收到之后重新
刷新 time-wait 时间。
进行可靠的断开连接确认。

使用 SOCKET 通信

服务端和客户端

如何确定服务端客户端?
通常发起请求的一段作为客户端,响应请求的一端作为服务端。

  • 创建服务端
var server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 服务端绑定到 IP 和 端口
server.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 65535));

// 开启监听
server.Listen();

// 等待客户端连接
Socket client = server.Accept();

// 我们使用 client 与客户端进行 TCP 通信。
  • 客户端连接到服务器
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

// 连接服务端
socket.Connect("127.0.0.1", 65535);

通信模式

  • 同步模式

我们使用不带 Async、Begain、End 类似这种方法进行 TCP 通信的模式为同步模式。
例如 BeginAccept(),ReceiveAsync(arg)这些方法是异步的
Accept()Receive(buffer)这些方法是同步的

// 阻塞接收数据,如果设置超时,可能会抛超时异常
var size = socket.Receive(buffer);
  • 异步模式
    • APM 异步模式

      // 开启一个异步接收5个字节
      var resulr = socket.BeginReceive(buffer, 0, 5, SocketFlags.None, (arg) =>
      {
          Console.WriteLine("接受完成回调!");
      }, null);
      
      // 阻塞等待接收完成,最多只接收5个字节
      var size = socket.EndReceive(resulr);
      
    • EAP 异步模式

      var arg = new SocketAsyncEventArgs();
      arg.Completed += Arg_Completed;
      socket.ReceiveAsync(arg);
      
      // 通过这种方式,还可以判断 TCP 另一端是否请求断开连接。
      private static void Arg_Completed(object? sender, SocketAsyncEventArgs e)
      {
          if (e.SocketError == SocketError.Success)
          {
              if (e.Buffer?.Length > 0)
                  Console.WriteLine(Encoding.UTF8.GetString(e.Buffer));
          }
      }
      
posted @ 2023-12-03 23:13  RafaelLxf  阅读(68)  评论(0)    收藏  举报