user-0 提问: TCP传输图片的问题

回复:
user: user-1
content: 2 3 4 5 6 typedef struct { unsigned int packet_num;//一次传送分包数量 unsigned int packet_index;//当前传送包的序号 unsigned char data[1024];//每个包的大小 }tcp_packet;

user: user-2
content: 我拿了你的代码学习了一下.顺便学习了VS2017,整了一天,调试发现,    根据图片显示的效果以及文件头正确 文件尾显示不正确,说明只接受到了数据包的前部分,后部分没有收到, 发现是你的发送和接收的缓存设置过大.   1M太大了,建议换成1024b,把数据包拆分发送,不存在丢失现象了,图片解析正确.

user: user-3
content: tcp发送和接收不是同步的 不能依赖发送一次就接收一次。 tcp没有保证一次能把你要发送的发送完整，同样接收也是这样。 要根据send或者recv返回的值，判断是否发送或者接收完整。不完整就继续发送或者接收。 发送和接收的过程不是一次，需要在循环中进行，完整了才退出循环。

user: user-3
content: 引用 21 楼 HANKER131523 的回复:[quote=引用 18 楼 ananluowei 的回复:] tcp发送和接收不是同步的 不能依赖发送一次就接收一次。 tcp没有保证一次能把你要发送的发送完整，同样接收也是这样。 要根据send或者recv返回的值，判断是否发送或者接收完整。不完整就继续发送或者接收。 发送和接收的过程不是一次，需要在循环中进行，完整了才退出循环。 你说的对，可是send和recv函数里面有一个包的字节数的参数，这个一般要选多大了，我试了好多次，发现几M貌似都可以的，而且单次发单次收都没什么问题[/quote] 一个包的大小是无所谓的，只要发送过去的格式，接收方能解析，能知道这个包多大就可以。发送和接收的过程不是一次send或者recv的，给你看一个简单的发送接收的函数代码//增加一个send、recv共用的函数，减少重复代码  int sendrecv(SOCKET sock, char* buff, unsigned int len, bool sendflag) { 	int ret = 0; 	do 	{ 		int i; 		if (sendflag) //发送标志，接收为false 			i = send(sock, buff + ret, len - ret, 0); 		else 			i = recv(sock, buff + ret, len - ret, 0); 		if (i == 0) 		{ 			//cout << "connect closed\n"; 			ret = i; 			break; 		} 		else if (i < 0) 		{ 			//cout << "recv failed with error: " << WSAGetLastError() << endl; 			ret = i; 			break; 		} 		else 		{	 			ret += i; 		} 	} while (ret >0 && ret < len); 	return ret; }   inline int recvtobuff(SOCKET sock, char* buff, unsigned int len) { 	return sendrecv(sock, buff, len, false); }  inline int sendfrombuff(SOCKET sock, char* buff, unsigned int len) { 	return sendrecv(sock, buff, len, true); }

user: user-4
content: 引用 20 楼 HANKER131523 的回复:[quote=引用 19 楼 chenandczh 的回复:] 包协议里面 应该添加 一些信息细节 。例如 ，图片总的BYTE大小，总包数，当前包序号，这样就能保证接收后数据整合处理。 兄弟，你看程序了吗，里面有的[/quote] 有跟逻辑正确是两码事，既然有这个思路，为什么不去调一下，完成接收后对比总包数以及计算一下文件MD5和采集收集的全部字节的MD5是否在一致。等你确认收集过程没有问题再看看是不是图片解码问题。

user: user-0
content: 引用 18 楼 ananluowei 的回复:tcp发送和接收不是同步的 不能依赖发送一次就接收一次。 tcp没有保证一次能把你要发送的发送完整，同样接收也是这样。 要根据send或者recv返回的值，判断是否发送或者接收完整。不完整就继续发送或者接收。 发送和接收的过程不是一次，需要在循环中进行，完整了才退出循环。 你说的对，可是send和recv函数里面有一个包的字节数的参数，这个一般要选多大了，我试了好多次，发现几M貌似都可以的，而且单次发单次收都没什么问题

user: user-0
content: 引用 19 楼 chenandczh 的回复:包协议里面 应该添加 一些信息细节 。例如 ，图片总的BYTE大小，总包数，当前包序号，这样就能保证接收后数据整合处理。 兄弟，你看程序了吗，里面有的

user: user-4
content: 包协议里面 应该添加 一些信息细节 。例如 ，图片总的BYTE大小，总包数，当前包序号，这样就能保证接收后数据整合处理。

user: user-5
content: 这么复杂的程序，佩服，一个菜鸟的我表示看不懂，写这个程序语言多久？要向你学习

user: user-6
content: 发送时，检查下send返回值，看下是否全部成功了，建议分多次发送，每次发送一小块。 tcp是流式的，不一定就是服务器发了一个数据包，客户端就收到一个数据包

user: user-7
content: TCP不仅是可靠不丢包，而且保证了顺序，除非连接被重置，否则根本不需要关心这些问题。

user: user-0
content: 引用 9 楼 hzy_76 的回复:那就更是跟发送顺序无关了，要知道TCP的基本特点正是“可靠连接”，数据顺序都要自己处理了，干嘛不用UDP？  [quote=引用 8 楼 HANKER131523 的回复:] [quote=引用 7 楼 hzy_76 的回复:] TCP协议应该已经保证了数据的顺序，除非你重新创建了socket连接。所以应该不是这方面的问题。 你可以标记一下数据，调试看看发送的每个数据包和对端收到的都是什么。 我现在只是用了一次发送和一次接收来测试[/quote][/quote] TCP不是说可靠不丢包吗，这个也不是我一个人决定的，也本着学东西的态度试试

user: user-0
content: 引用 10 楼 cfjtaishan 的回复:[quote=引用 5 楼 HANKER131523 的回复:] [quote=引用 2 楼 cfjtaishan 的回复:] 有可能是网络动荡，即服务器是顺序发送的，但是到客户端收到的数据可能不是按照一个个接收，有可能一下子接收到2个包（即服务器发2次，客户端一次接收）这就是为什么如果中间不加包头包尾图片就正常； 解决网络动荡的方法是客户端使用环形缓冲区，也可以理解为缓冲队列；每个收到的包先存到缓冲队列里，然后再从缓冲队列里取数据解析，即使每个从服务到的数据都加了包头和包尾，我们从缓冲队列里取数据然后分别解析，如果收到的包头（包头里有数据长度吧）都包含数据长度，那么根据这个长度和缓存队列里的数据长度比较，若包头里记录的长度大于当前缓存队列里数据长度，那么则不读取，反之则读取解析（去掉包头和包尾）  有可能是网络动荡，即服务器是顺序发送的，但是到客户端收到的数据可能不是按照一个个接收，有可能一下子接收到2个包（即服务器发2次，客户端一次接收）这就是为什么如果中间不加包头包尾图片就正常；，这句话不太理解，感觉没什么关系啊[/quote] 网络动荡是指网络有可能好有可能不好；如果网络好，服务器发送一个，客户端马上收到了，这个我们想要的，但是有时候网络不像我们那样想的顺畅；不然我们下载东西，怎么会有时候快，有时候慢呢。[/quote] 我用的是本机的127.0.0.1，应该不存在动荡的问题吧

user: user-8
content: 引用 11 楼 HANKER131523 的回复:[quote=引用 10 楼 cfjtaishan 的回复:] [quote=引用 5 楼 HANKER131523 的回复:] [quote=引用 2 楼 cfjtaishan 的回复:] 有可能是网络动荡，即服务器是顺序发送的，但是到客户端收到的数据可能不是按照一个个接收，有可能一下子接收到2个包（即服务器发2次，客户端一次接收）这就是为什么如果中间不加包头包尾图片就正常； 解决网络动荡的方法是客户端使用环形缓冲区，也可以理解为缓冲队列；每个收到的包先存到缓冲队列里，然后再从缓冲队列里取数据解析，即使每个从服务到的数据都加了包头和包尾，我们从缓冲队列里取数据然后分别解析，如果收到的包头（包头里有数据长度吧）都包含数据长度，那么根据这个长度和缓存队列里的数据长度比较，若包头里记录的长度大于当前缓存队列里数据长度，那么则不读取，反之则读取解析（去掉包头和包尾）  有可能是网络动荡，即服务器是顺序发送的，但是到客户端收到的数据可能不是按照一个个接收，有可能一下子接收到2个包（即服务器发2次，客户端一次接收）这就是为什么如果中间不加包头包尾图片就正常；，这句话不太理解，感觉没什么关系啊[/quote] 网络动荡是指网络有可能好有可能不好；如果网络好，服务器发送一个，客户端马上收到了，这个我们想要的，但是有时候网络不像我们那样想的顺畅；不然我们下载东西，怎么会有时候快，有时候慢呢。[/quote] 我用的是本机的127.0.0.1，应该不存在动荡的问题吧[/quote] 如果是本地的服务器和客户端，那么不存在网络动荡问题，但是需要考虑CPU调用机制，因为在同一台电脑上，服务器和客户端是属于不同的两个进程，因此他们的通信可以简单的理解为进程间通信（异步的），这样也可能出现类似网络动荡的问题，比如给服务器的时间片多一些，给客户端的时间片少一些。

user: user-9
content: 不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊！ http://bbs.csdn.net/topics/380167545

user: user-8
content: 引用 5 楼 HANKER131523 的回复:[quote=引用 2 楼 cfjtaishan 的回复:] 有可能是网络动荡，即服务器是顺序发送的，但是到客户端收到的数据可能不是按照一个个接收，有可能一下子接收到2个包（即服务器发2次，客户端一次接收）这就是为什么如果中间不加包头包尾图片就正常； 解决网络动荡的方法是客户端使用环形缓冲区，也可以理解为缓冲队列；每个收到的包先存到缓冲队列里，然后再从缓冲队列里取数据解析，即使每个从服务到的数据都加了包头和包尾，我们从缓冲队列里取数据然后分别解析，如果收到的包头（包头里有数据长度吧）都包含数据长度，那么根据这个长度和缓存队列里的数据长度比较，若包头里记录的长度大于当前缓存队列里数据长度，那么则不读取，反之则读取解析（去掉包头和包尾）  有可能是网络动荡，即服务器是顺序发送的，但是到客户端收到的数据可能不是按照一个个接收，有可能一下子接收到2个包（即服务器发2次，客户端一次接收）这就是为什么如果中间不加包头包尾图片就正常；，这句话不太理解，感觉没什么关系啊[/quote] 网络动荡是指网络有可能好有可能不好；如果网络好，服务器发送一个，客户端马上收到了，这个我们想要的，但是有时候网络不像我们那样想的顺畅；不然我们下载东西，怎么会有时候快，有时候慢呢。

user: user-7
content: 那就更是跟发送顺序无关了，要知道TCP的基本特点正是“可靠连接”，数据顺序都要自己处理了，干嘛不用UDP？  引用 8 楼 HANKER131523 的回复:[quote=引用 7 楼 hzy_76 的回复:] TCP协议应该已经保证了数据的顺序，除非你重新创建了socket连接。所以应该不是这方面的问题。 你可以标记一下数据，调试看看发送的每个数据包和对端收到的都是什么。 我现在只是用了一次发送和一次接收来测试[/quote]

user: user-0
content: 引用 7 楼 hzy_76 的回复:TCP协议应该已经保证了数据的顺序，除非你重新创建了socket连接。所以应该不是这方面的问题。 你可以标记一下数据，调试看看发送的每个数据包和对端收到的都是什么。 我现在只是用了一次发送和一次接收来测试

user: user-7
content: TCP协议应该已经保证了数据的顺序，除非你重新创建了socket连接。所以应该不是这方面的问题。 你可以标记一下数据，调试看看发送的每个数据包和对端收到的都是什么。

user: user-0
content: 引用 4 楼 cfjtaishan 的回复:[quote=引用 3 楼 HANKER131523 的回复:] [quote=引用 2 楼 cfjtaishan 的回复:] 有可能是网络动荡，即服务器是顺序发送的，但是到客户端收到的数据可能不是按照一个个接收，有可能一下子接收到2个包（即服务器发2次，客户端一次接收）这就是为什么如果中间不加包头包尾图片就正常； 解决网络动荡的方法是客户端使用环形缓冲区，也可以理解为缓冲队列；每个收到的包先存到缓冲队列里，然后再从缓冲队列里取数据解析，即使每个从服务到的数据都加了包头和包尾，我们从缓冲队列里取数据然后分别解析，如果收到的包头（包头里有数据长度吧）都包含数据长度，那么根据这个长度和缓存队列里的数据长度比较，若包头里记录的长度大于当前缓存队列里数据长度，那么则不读取，反之则读取解析（去掉包头和包尾） 你意思是我每次接收的数据都设置为很小，然后多次接收，那这个大小一般应该设置为多大呢[/quote] 我说的环形缓冲区，建议从网上找一个这个技术点；这个需要多线程操作了，即在客户端用一个线程去接收写到环形缓冲区里，一个线程去读环形缓冲区，然后解析数据报文；[/quote] 我这个程序里含有用数组实现的缓冲区程序的，只是，我前面发现1M左右的图片直接发过来好像就能接受成功，就不用了