1. 流协议与粘包
TCP是基于字节流的传输服务,这意味着TCP传送的数据之间是没有边界的。
UDP是基于消息的传输服务,它传输的是报文(数据报),是具有边界的。
字节流传输时不能保证对方接受到的是一个消息还是多个消息,所以会产生粘包问题
基于消息传输的协议来说,能够保证对等方一次读操作只能返回一条消息。
2.粘包差生的原因
a.应用层的缓冲区大小超过套接口发送缓冲区大小(消息被分割)
b.TCP传输受最大段MSS限制
c.链路层传输的数据受最大传输单元MTU的限制
d.流量控制,拥塞控制,延迟发送等机制
3.粘包处理方案
本质上在应用层自己维护消息与消息的边界
a.定长报(以定长的形式发送,对等方也以定长的形式接受)
b.包尾部加\r\n(ftp协议就用到这种方式,如果消息中本来含有\r\n 可能用到转义方式解决)
c.包头加上包体的长度
d.可以设计更复杂的应用层协议
4.readn/writen 的封装
接受/发送确切数据的操作
方法一:定长报文(在没有接受或者发送到指定长度的报文一直接受或者发送)
方法二:加上传输数据的长度
struct packet
{
int len; //报头,在接受时先接受报头,确定包体的实际大小
char buff[1024]; //报体
}
TCP是基于字节流的传输服务,这意味着TCP传送的数据之间是没有边界的。
UDP是基于消息的传输服务,它传输的是报文(数据报),是具有边界的。
字节流传输时不能保证对方接受到的是一个消息还是多个消息,所以会产生粘包问题
基于消息传输的协议来说,能够保证对等方一次读操作只能返回一条消息。
2.粘包差生的原因
a.应用层的缓冲区大小超过套接口发送缓冲区大小(消息被分割)
b.TCP传输受最大段MSS限制
c.链路层传输的数据受最大传输单元MTU的限制
d.流量控制,拥塞控制,延迟发送等机制
3.粘包处理方案
本质上在应用层自己维护消息与消息的边界
a.定长报(以定长的形式发送,对等方也以定长的形式接受)
b.包尾部加\r\n(ftp协议就用到这种方式,如果消息中本来含有\r\n 可能用到转义方式解决)
c.包头加上包体的长度
d.可以设计更复杂的应用层协议
4.readn/writen 的封装
接受/发送确切数据的操作
方法一:定长报文(在没有接受或者发送到指定长度的报文一直接受或者发送)
缺点:增加网络的负担假如固定长度为1024,实际有效的数据只有5个字符
//要接受确定的count字节数
ssize_t readn(int fd,void *buf,size_t count) //size_t是无符号的整数ssize_t是有符号的整数
{
size_t nleft =count ;//剩余的字节数
size_t nread; //已经接受的字节数
char *bufp =(char *)buf;
while(nleft > 0)
{
if(nread =read(fd,bufp,nleft)<0)
{
if(errno ==EINTR ) //全局变量errno值为EINTR 表示信号被中断了.,这种情况不认为是失败了
{
continue;
}
else
{
return -1;
}
}
else if(nread == 0) //说明对等方关闭了
{
return count - nleft ;
}
else
{
bufp +=nread;
nleft -=nread;
}
}
return count;
}
ssize_t writen(int fd,const void *buf,size_t count)
{
size_t nleft =count ;//剩余的字节数
ssize_t nwriten; //已发送的字节数
char *bufp =(char *)buf;
while(nleft > 0)
{
if(nwriten =read(fd,bufp,nleft)<0)
{
if(errno ==EINTR ) //全局变量errno值为EINTR 表示信号被中断了.,这种情况不认为是失败了
{
continue;
}
else
{
return -1;
}
}
else if(nwriten == 0) //说明什么都没有发送
{
continue;
}
else
{
bufp +=nwriten;
nleft -=nwriten;
}
}
return count;
}
方法二:加上传输数据的长度
struct packet
{
int len; //报头,在接受时先接受报头,确定包体的实际大小
char buff[1024]; //报体
}