socket如何封包,解包 简单易懂点!

qq_33553286 2018-08-20 10:52:01
最近用socket传输文件, 服务端循环文件二进制数据, 发送给客户端, 客户端建立一个文件循环写入, 可是客户端的recv会堵塞住, 得服务器循环发完文件后关闭客户端socket , 这样客户端就会收到FIN 包, 得以退出循环, 使得文件传输可以写出, 而我就是想要解决这一问题, 不用每次发完都得断开客户端! 代码:
while( (nCount = recv(clntSock, buffer, BUF_SIZE, 0)) > 0 ){
fwrite(buffer, nCount, 1, fp);
}
读取完缓冲区中的数据 recv() 并不会返回 0,而是被阻塞 然后文件就写不出! 就必须的服务端发送关闭, recv才会返回0, 得以脱坑! 这样的话我要该怎么做, 简单点! 谢谢大家!
...全文
1168 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
只此冒泡君 2018-08-23
  • 打赏
  • 举报
回复
引用 15 楼 qq_33553286 的回复:
用大家所提供的方法 已解决 谢谢你们!

结贴给分
「已注销」 2018-08-23
  • 打赏
  • 举报
回复
用大家所提供的方法 已解决 谢谢你们!
smwhotjay 2018-08-22
  • 打赏
  • 举报
回复
结构体可以用,但要用的巧妙,和其他程序对接时,对齐成了问题,考虑跨语言
yiyefangzhou24 2018-08-22
  • 打赏
  • 举报
回复
引用 5 楼 a34140974 的回复:
[quote=引用 2 楼 yiyefangzhou24 的回复:]
你BUF_SIZE太大的话一次是发不完的,需要分包,最简单的就是用一个结构体分包发送

typedef struct
{
unsigned int packet_num;//一次传送分包数量
unsigned int packet_index;//当前传送包的序号
unsigned char data[1024];//每个包的大小
}tcp_packet;

我是不建议发结构体,处理起来有点麻烦,还得考虑不同机器的对齐,而且一样会出现楼主问的问题。接收端逻辑如果需要很完备,很复杂的[/quote]
逻辑上不复杂,接收和发送不会超过100行代码,我用结构体做过远程桌面的传输,简单、健壮、有效
Chelios_Lee 2018-08-22
  • 打赏
  • 举报
回复
定长 + 收尾校验, 很多网络应用协议都是这么干的
只此冒泡君 2018-08-22
  • 打赏
  • 举报
回复
直接多线程 不就行了么 辣么复杂么
z0123501501 2018-08-22
  • 打赏
  • 举报
回复
struct TCPPack
{
unsigned long long dwDalaLong=0ULL;
char szBlock[10240];
unsigned long long dwVerify=0ULL;
unsigned long long EndFlag=0ULL;
};
封包就是把每次发送的数据打包成上面的形式,例如
数据block要发送到socket sock
stringstream sstr;sstr.write(block,block_len);
发送的时候这样处理
unsigned long long reserve1=0ULL;
while(剩余数据>0)
{
unique_ptr<TCPPack> a(new TCPPack);
//.....计算校验码
a->dwVerify=校验码;//具体方式自己实现
a->EndFlag=0ULL;//结束包,是则为1
sstr.read(a->szBlock,10240);
重新发送:
send(sock,reinterpret_cast<char*>(&*a),10240,0);
if(recv(sock,(char*)&reserve1,sizeof(unsigned long long),0)<0);// 出错处理
switch(reserve1)
{
case 验证出错:
goto 重新发送;
case 中断:
return FALSE;
case 继续发送:
break;
}
}
下面是处理剩余包。。。
if(体积%10240){/*...... 同上*/}
然后是处理尾包
unique_ptr<TCPPack> a(new TCPPack);
//.....计算校验码
a->dwVerify=校验码;//具体方式自己实现
a->EndFlag=1ULL;//结束包,是则为1
// ......同上,也要处理出错
这就是封包。解包原理相同,这种响应包稳得不行,如果需要什么别的内容可以加进去struct里面,例如数据类型、队列顺序之类的。。。
校验可以改成 char CRC[33];(省一个字节也可以)
至于对齐,pack成1就行。当然建议用uint64_t之类的类型,然后对齐成1。
由于是TCP,那就不需要什么序号了,保证顺序的,多此一举。倒是校验和出错、断点续传需要处理一下。
注意接收端需要recv(...,...,...,MSG_WAITALL);
赵4老师 2018-08-21
  • 打赏
  • 举报
回复
不知道有多少前人掉在TCP Socket
send(人多)send(病少)send(财富)
recv(人多病)recv(少财富)
陷阱里面啊!
http://bbs.csdn.net/topics/380167545
smwhotjay 2018-08-21
  • 打赏
  • 举报
回复
https://blog.csdn.net/smwhotjay/article/details/77744644
后面写了 1.11网络引擎内部数据协议
就是如何封包
轻箬笠 2018-08-21
  • 打赏
  • 举报
回复
引用 5 楼 a34140974 的回复:
[quote=引用 2 楼 yiyefangzhou24 的回复:]
你BUF_SIZE太大的话一次是发不完的,需要分包,最简单的就是用一个结构体分包发送

typedef struct
{
unsigned int packet_num;//一次传送分包数量
unsigned int packet_index;//当前传送包的序号
unsigned char data[1024];//每个包的大小
}tcp_packet;

我是不建议发结构体,处理起来有点麻烦,还得考虑不同机器的对齐,而且一样会出现楼主问的问题。接收端逻辑如果需要很完备,很复杂的[/quote]
结构体的对齐不是什么问题,设置一下就可以了。比如#pragma pack(1)。


其实楼主还可以考虑用http发送文件。由服务端告诉客户端一个下载地址,客户端下完,返回要给下载成功即可。上传也是类似的
月凉西厢 2018-08-21
  • 打赏
  • 举报
回复
引用 2 楼 yiyefangzhou24 的回复:
你BUF_SIZE太大的话一次是发不完的,需要分包,最简单的就是用一个结构体分包发送

typedef struct
{
unsigned int packet_num;//一次传送分包数量
unsigned int packet_index;//当前传送包的序号
unsigned char data[1024];//每个包的大小
}tcp_packet;

我是不建议发结构体,处理起来有点麻烦,还得考虑不同机器的对齐,而且一样会出现楼主问的问题。接收端逻辑如果需要很完备,很复杂的
sghcpt 2018-08-21
  • 打赏
  • 举报
回复
引用 1 楼 qq_33553286 的回复:
我看过一些网上代码, 完全看不懂 所以来提问了


个人理解:楼主,可以在发生文件前,把文件的一些基本信息,例如文件大小之类发给客户端,客户端那边收到就保存下来文件的大小,在客户端的recv函数中统计接受到的实际文件大小,然后跟服务器之前发送过来的文件大小比较,如果等于之前的服务器发送过来的文件大小,就可以跳出循环了。。
yiyefangzhou24 2018-08-21
  • 打赏
  • 举报
回复
你BUF_SIZE太大的话一次是发不完的,需要分包,最简单的就是用一个结构体分包发送

typedef struct
{
unsigned int packet_num;//一次传送分包数量
unsigned int packet_index;//当前传送包的序号
unsigned char data[1024];//每个包的大小
}tcp_packet;
半雨微凉丶 2018-08-21
  • 打赏
  • 举报
回复
异步socket?
「已注销」 2018-08-20
  • 打赏
  • 举报
回复
我看过一些网上代码, 完全看不懂 所以来提问了
1、本课程是一个干货课程,主要讲解如何封装服务器底层,使用Tcp/ip长连接,IDE使用vs2019 c++开发以及使用c++11的一些标准,跨平台windows和linux,服务器性能高效,单服务器压力测试上万无压力,服务器框架是经历过上线产品的验证,框架简单明了,不熟悉底层封装的人,半个小时就能完全掌握服务器框架上手写业务逻辑。2、本课程是一个底层服务器框架教程,主要是教会学员在windows或linux下如何封装一个高效的,避免踩坑的商业级框架,服务器底层使用初始化即开辟内存的技术,使用内存池,服务器运行期间内存不会溢出,非常稳定,同时服务器使用自定义哈希hashContainer,在处理新的连接,新的数据,新的封包,以及解包,发包,粘包的过程,哈希容器性能非常高效,增、删、查、改永远不会随着连接人数的上升而降低性能,增、删、查、改的复杂度永远都是恒定的O(1)。3、服务器底层封装没有使用任何第三方网络库以及任何第三方插件,自由度非常的高,出了任何BUG,你都有办法去修改,查找问题也非常方便,在windows下使用iocp,linux下使用epoll.4、讲解c++纯客户端,主要用于服务器之间通信,也就是说你想搭建多层结构的服务器,服务器与服务器之间使用socket通信。还可以使用c++客户端做压力测试,开辟多线程连接服务器,教程提供了压力测试,学员可以自己做压力测试服务器性能。5、赠送ue4和unity3d通信底层框架以及多人交互demo,登录,注册,玩家离开,同步主要是教会学员服务器与客户端如何交互。6、赠送c++连接mysql数据库框架demo,登录,注册,玩家离开数据持久化.7、服务器教程使用自定义通信协议,同时也支持protobuf,选择权在开发者自己手里,想用什么协议都可以,自由度高。8、服务器教程使用手动敲代码逐句讲解的方式开展教学课程。非喜勿喷,谢谢大家。9、服务器教程提供源码,大家可以在平台提供的地址下载或者联系我,服务器使用c++11部分标准,std::thread,条件变量,线程锁,智能指针等,需要学员具备一定c++知识,购买前请慎重考虑。

64,682

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧