客户端:
第一次:send(fd, buf, 30, 0);假设你的文件名和文件长度组成的buf一共30
第二次:send(fd,buf,filelength,0);将长度为filelength的内容发出去 (其实这里2次发送都要对发送长度做判断的,需要判断发送的长度是否是30或者filelength)
服务端:
第一次:recv(fd,buf,30,0);
解析长度为30的buf,得到filename和filelength
第二次:recv(fd,buf,filelength,0) (同样的这2次recv都要对recv的返回值做判断,收到的长度是否是30或者filelength)
当网络断开的时候是不是也是客户端断开呢,这个时候客户端只发了一半呢,怎么办
第二种情况,客户端发了200,你却只收了100,请问这是一个完整的文件吗
东方巽雷
23
如果使用recv(fd,buf,filelength,0)来接收,而不是像我那样分批接收。假如发送的文件是1G大小,那您岂不是要消耗1G内存来分配给buf?如果发送的文件十几G,那一般人的计算机都会死机了吧。
给你发一段收发数据的代码,下面的代码中调用Socket::write或这Socket::read后都要对返回值做判断,即与他们的参数len做判断,凡是不等于len的返回值都是有问题的
//写数据
int Socket::write(const char *data, int len)
{
if (_sockfd == -1)
{
return -1;
}
int lenToWritten = len;
int totalLenWritten = 0;
while(lenToWritten > 0)
{
int tmpLen;
do {
tmpLen = ::write(_sockfd, data+totalLenWritten, lenToWritten);
if(errno == EPIPE) //broken pipe 如果客户端或服务器断开连接,此时为断开的管道,无法写入,直接return
{
perror("error ");
return -1;
}
if(tmpLen == 0)
{
perror("error");
return -1;
}
} while (tmpLen < 0 /*&& errno == EINTR*/);
lenToWritten -= tmpLen;
totalLenWritten += tmpLen;
}
qDebug() << "totalLenWritten = " << totalLenWritten;
return totalLenWritten;
}
//读数据
int Socket::read(char *data, int len)
{
if (_sockfd == -1)
{
return -1;
}
int lenToRead = len;
int totalLenRead = 0;
while(lenToRead > 0)
{
int tmpLen;
do {
tmpLen = ::read(_sockfd, data+totalLenRead, lenToRead);
if(tmpLen == 0)
{
qDebug() << "连接断开";
return -1;
}
if(errno == EPIPE)
{
perror("error");
return -1;
}
} while (tmpLen < 0 /*&& errno == EINTR*/);
lenToRead -= tmpLen;
totalLenRead += tmpLen;
}
qDebug() << "totalLenRead = " << totalLenRead;
return totalLenRead;
}
缓冲区没那么大,当进行写的时候,写缓冲区已满,你是写不进去的,所以一般读和写都是循环
东方巽雷
26
Socket::read(char data,int len)函数就是将len长度的数据可靠地保存到data指向的内存区域吧。函数内没发现将data写到文件的操作,只是不断移动data指针。所以data指向的内存区域的大小就是文件大小吧。所以我认为这段代码没有解决大文件传输问题。
我这段代码只是针对网络传输,你要写文件只需将收到的内容write到文件中即可
大文件,你可以考虑一次发多少,如1M,分多少次发送,每次发送调用该函数就行了,并不是一次发送完
九号猪
29
以前用Qt写过一次C/S的程序。
TCP协议好像有个封包大小,就像adsl上网的tcp包默认大小一般是1492字节。一般来说,包越大传输越快,但这个默认包大小并不是固定值,网络质量不好,包小一点更好,可以避免发包经常出错(出错系统会自动重发,经常错就会经常重发)。
所以作为我们写程序,无法判断这个包到底是多大,也就不可能做到发送和接收动作是一一对应的。
发送的时候,可以简单地放入缓存,让协议自动发送,但接收的时候就必须做判断是否接收了一个完整的包。
一般解决这个方法,是发送一个大包时,在包头注明这个包的字节长度。
接收方首先接收并读取这个长度信息,然后循环接收,当接收的字节数达到长度时,停止接收进行处理。
然后再接收下一条内容。
九号猪
30
:lol还是Qt简单,直接把一个类序列化成字节流,接收时把字节流再还源成一个类。。。
也不用操心字节序的问题。