TCPIP网络编程 -- (五)基于 TCP 的服务端客户端(2)

TCP/IP网络编程 -- (五)基于 TCP 的服务端/客户端(2)

5.1回声服务器的完美实现

由于上一章末尾提到的问题

write(sock, message, strlen(message));
str_len = read(sock, message, BUF_SIZE - 1);
message[str_len] = 0;
printf("Message from server: %s", message);
  1. client 多次发送的数据被被一次性传给了 server,于是回传的时候把多条信息一起发过来了
  2. client 一次发送的数据太长,可能多次 write 才能写完,操作系统把数据分为了多个数据包,client 在没有收完所有数据包的时候就调用了read,于是把一条信息分成了多条打印出来

因此如果可以提前知道 client 一共要收多少字节的数据,就可以等全部收完了再打印

str_len = write(sock, message, strlen(message));
recv_len = 0;
while(recv_len < str_len) {
    recv_cnt = read(sock, &message[recv_len], BUF_SIZE - 1);
    if (recv_cnt == -1)
        error_handling("read() error");
    recv_len += recv_cnt;
}
message[str_len] = 0;
printf("Message from server: %s", message);

但这是基于回声服务器的方法,正常情况下客户端并不会事先知道要接收多少数据,因此需要靠应用层协议来解决,即解决粘包问题,例如 HTTP 设置回车符,换行符作为 HTTP header 的边界,用 Content-lenth 字段作为 HTTP body 的边界

《TCP/IP网络编程》中定义了一种简单的应用层协议来解决,思路是固定各类信息的长度,消息长度的信息也再服务器与客户端之间发送

5.2TCP原理

write函数调用后并非立即传输数据,而是将数据移至输出缓冲;

read函数调用后并非立即接受数据,而是将数据移至输入缓冲;

image

数据在在恰当的时候从字节的输出缓冲传入对方的输入缓冲

这些缓冲I/O的特点为

  1. I/O缓冲在每个TCP socket 中单独存在
  2. I/O缓冲在创建 socket 时自动生成
  3. 即使关闭 socket 也将继续输出缓冲中遗留的数据
  4. 关闭 socket 将丢失输入缓冲中的数据

TCP是全双工的,一个 socket 会创建如上图所示的两个流

posted @ 2023-03-14 17:26  hzy0227  阅读(32)  评论(0编辑  收藏  举报