SDL_net初体验-采取TCP协议进行数据传输需要注意的问题

使用TCP协议进行数据传输,可以提供可靠有序的数据传输,相比于HTTP每次请求都要建立和关闭连接,TCP连接一旦建立可以保持长时间的连接,适合需要持续通信的应用,但是由于TCP协议是面向流的协议,它将数据视为一个连续的字节流,而不是独立的消息。因此,发送端发送的数据可能会被拆分成多个数据包,或者多个小数据包可能会被合并成一个大的数据包发送到接收端。因此在使用TCP协议进行数据传输前需要额外解决以下几个问题:

粘包问题

  • 产生原因:

    1. 发送端的缓冲机制:TCP协议会将应用层的数据放入发送缓冲区,如果发送缓冲区中的数据量较小,TCP可能会将多个小数据包合并成一个大的数据包发送。
    2. 接收区同样存在接收缓冲区,若接收端应用程序读取速度较慢,接收缓冲区可能会积累多个数据包,读取时便会将这些数据包合并在一起。
  • 解决方案:

    1. 发送定长的消息,每个消息长度都是固定的,接收方每次只要读取固定长度的数据即可。
    2. 首尾识别符,使用特殊的识别符来标志数据的开始和结束。
    3. 数据头部添加长度信息,接收端先读取长度信息,再根据此信息去读取数据

大小端问题

  • 产生原因: 大小端问题是指两种不同的字节存储方式,大端序会将高字节存储在低地址,小端序则相反,例如存储0x 12 34 56 78时,在大端序会将其存储为12 34 56 78,小端序则会存储为78 56 34 12,在涉及存储和传输多字节数据时,均可能出现大小端问题。
  • 解决方案: 发送端和接收端都将数据转换为网络字节序(即大端序),在SDL_net中在发送长度信息前调用SDL_SwapBE32,将长度信息转换为网络字节序,在接收信息时,也调用SDL_SwapBE32将网络字符序转换为主机字符序
    1
    2
    3
    int networkLength;
    memcpy(&networkLength, buffer + bufferOffset, sizeof(int));
    int length = SDL_SwapBE32(networkLength); // 转换为主机字节序
    1
    2
    3
    int length = timestamp.length() + 1;
    int networkLength = SDL_SwapBE32(length); // 转换为网络字节序
    SDLNet_TCP_Send(client, &networkLength, sizeof(networkLength)); // 发送消息长度

    SDL_SwapBE32原理是当主机字节序为小端字节序时会对字节序进行反转,反之则不变

分段问题

  • 产生原因: TCP 是一种流协议,它不保证每次发送的数据包会以相同的大小和顺序到达接收端,数据可能会被分成多个片段发送。
  • 解决方案: 对数据是否完整接收进行判断,若不完整则持续接收信息直到完整接收再进行读取。

SDL_net初体验-采取TCP协议进行数据传输需要注意的问题
http://example.com/2024/10/05/SDL_net初体验-采取TCP协议进行数据传输需要注意的问题集/
作者
FlyingfishFantasticfan
发布于
2024年10月5日
许可协议