c++ socket学习(1.4)

本文学习相关资料:
C/C++ socket编程教程

环境:vs2015
源码:本文代码

前面学到了TCP怎么循环发包,但是TCP连接的话会出现一个问题粘包

TCP连接接收到的数据并不是马上读取到内存里面的,而是放在缓冲区,让后调用recv函数来从缓冲区读取数据。

当然缓冲区是有大小限制

这时候就可能会出现粘包了。

1、假如客户端发送的数据很少,但次数多;服务端一次读取得多,就会将多次发送的内容全部读到一起。
2、假如一次客户端发送的数据很多,服务端一次没有读取完,那么就会还有剩下的数据在缓冲区;这时客户端第二次发送数据过来,和前一次读剩下的数据一起放。这时服务端又来读取数据了,就会出现了第一次读剩下的数据和第二次的部分数据被服务端一起读取。

来看看怎么实现这样的情况

情况1:

服务端

int maxlen = 200;
//接受客户端的连接
SOCKET client = accept(servSock, (sockaddr*)&clntAddr, &nSize);while (1) {//通过sleep来让客户端信息全部发送到缓冲区,让服务器能够一次读取完Sleep(1000);//接受到信息int len = recv(client, buf, maxlen, 0);std::string s(buf);if (s.compare("exit") == 0) {std::cout << "接收到关闭信息,关闭服务器" << std::endl;break;}std::cout << s << " " << len << std::endl;}closesocket(client);

客户端

int num = 5;
connect(client, (sockaddr*)&servAddr, sizeof(sockaddr));std::string s("1234");
for (int i = 0; i < num; ++i)std::cout << send(client, s.c_str(), s.size(), 0) << std::endl;//注意不要把字符串最后面那个'\0'也发送了
send(client, "\0", 1, 0);
//让服务端先读取完前面的内容在发送结束
Sleep(4000);
s = "exit";
std::cout << send(client, s.c_str(), s.size() + 1, 0) << std::endl;closesocket(client);

情况2:

服务端

int maxlen = 5; //注意这里不同了,表示服务端一次读取得少
//接受客户端的连接
SOCKET client = accept(servSock, (sockaddr*)&clntAddr, &nSize);while (1) {//通过sleep来让客户端信息全部发送到缓冲区,让服务器能够一次读取完//Sleep(1000); 睡眠也注释了//接受到信息int len = recv(client, buf, maxlen, 0);std::string s(buf);if (s.compare("exit") == 0) {std::cout << "接收到关闭信息,关闭服务器" << std::endl;break;}std::cout << s << " " << len << std::endl;}closesocket(client);

客户端

int num = 5;
connect(client, (sockaddr*)&servAddr, sizeof(sockaddr));std::string s("12345679"); //这里不同了,表示客户端一次发送得多
for (int i = 0; i < num; ++i)std::cout << send(client, s.c_str(), s.size(), 0) << std::endl;//注意不要把字符串最后面那个'\0'也发送了
send(client, "\0", 1, 0);
//让服务端先读取完前面的内容在发送结束,不然会读到最后面那个'\0',和exit拼在了一起,就不会结束了
Sleep(4000);
s = "exit";
std::cout << send(client, s.c_str(), s.size() + 1, 0) << std::endl;closesocket(client);

怎么解决粘包呢?
1、约定好每次读取的数据长度,每次发送的数据长度,保证一次读完
2、约定好每段发送数据的结束符,当读到这个结束符的时候表明读取完了第一次发送的数据,结束符后面的内容属于第二次发送的数据。

方法一比较简单,就只是改个数值就可以了
来看看方法二要怎么做:

客户端

int num = 5;
connect(client, (sockaddr*)&servAddr, sizeof(sockaddr));std::string s("12345679A"); //这里确定每次发送的数据长度为10字节,A表示数据结束
for (int i = 0; i < num; ++i)std::cout << send(client, s.c_str(), s.size(), 0) << std::endl;
Sleep(4000);
s = "exit";
std::cout << send(client, s.c_str(), s.size() + 1, 0) << std::endl;closesocket(client);

服务端

SOCKET client = accept(servSock, (sockaddr*)&clntAddr, &nSize);
char temp[maxlen];
memset(temp, 0, sizeof(temp));
//通过sleep来让客户端信息全部发送到缓冲区,让服务器能够一次读取完
Sleep(1000);//表示读取缓冲区的内容的下标
int vBufSite = 0;
int len = recv(client, buf, 7, 0); //一次读7个字节,肯定是要读两次的
while (1) {int vTempSite = 0;bool vRead = true;while (vRead) {if (vBufSite >=len) { //看看前一次读取的内容是不是包含了两次发送的内容len = recv(client, buf, 7, 0);vBufSite = 0;}while(vBufSite < len ) { //看看是不是包含了两次发送的内容if (buf[vBufSite] == 0) {vRead = false;temp[vTempSite] = 0;++vBufSite;break;}else if (buf[vBufSite] != 'A') { //读到分隔符就结束temp[vTempSite++] = buf[vBufSite];++vBufSite;}else {vRead = false;temp[vTempSite] = 0;++vBufSite;break;}}}std::string s(temp);if (s.compare("exit") == 0) {std::cout << "接收到关闭信息,关闭服务器" << std::endl;break;}std::cout << s << std::endl;temp[0] = 0;
}
closesocket(client);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/376286.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mongodb中分页显示数据集的学习

mongodb中分页显示数据集的学习 这次继续看mongodb中的分页。首先依然是插入数据&#xff1a; 1&#xff09; db.Blog.insert( { name : "Denis", age : 20, city : "Princeton" } ) db.Blog.insert( { name : "Abe", age : 30, city : &quo…

学习编程,英语很重要!!

学会编程&#xff0c;可能不需要英语多好&#xff0c;但是学号编程&#xff0c;英语真的很重要&#xff01;&#xff01;&#xff01; 好多文档&#xff0c;demo全是英文的&#xff0c;蛋疼&#xff0c;应许需要学习&#xff01;&#xff01;&#xff01;转载于:https://www.cn…

c++ socket学习(1.5)

本文学习相关资料&#xff1a; C/C socket编程教程 环境&#xff1a;vs2015 源码&#xff1a;本文代码 这次来试一下使用TCP来传输文件&#xff0c;其实传输数据和差不多&#xff0c;就是多一个读取文件&#xff0c;和一个写文件而已。 服务端 int readlan 100; std::ifst…

matlab生成HEX文件-任意信号 大于64K长度

HEX文件格式不赘述&#xff0c;写里直接放上代码。请批评改正。 1 %%convert a signal data into hex file format2 % data format:16bit 3 % signal length: less than 2^24-14 % author: Yang Li yangli0534gmail.com5 % data:2015.01.276 7 clear all;8 close all;9 clc; 10…

移动端网页中ViewPort的使用

<meta name"viewport" content"widthdevice-width,target-densitydpihigh-dpi, initial-scale1.0, minimum-scale1.0, maximum-scale1.0, user-scalableno"> <meta name”viewport” content”widthdevice-width, initial-scale1.0, user-scalabl…

c++ socket学习(1.6)

本文学习相关资料&#xff1a; C/C socket编程教程 环境&#xff1a;vs2015 源码&#xff1a;本文代码 这次来看看UDP 之前在c socket学习&#xff08;1.2&#xff09;讲过UDP怎么发送了&#xff0c;那现在来做一个可以一直发送的。 这次没有什么接收端和发送端了&#xff0…

redis学习笔记——(1)

1. NoSQL&Redis介绍 NoSQL&#xff0c;Not Only SQL&#xff0c;是非关系型的数据库。传统的关系数据库不能满足超大规模和高并发的应用。 是以Key-Value的形式存储&#xff0c;&#xff08;例如JSON,XML&#xff09;&#xff0c;不一定遵循传统数据库的一些基本要求&#…

命令模式坚决svn树冲突(local unversioned, incoming add upon update)

当工作目录修改删除过时更新使用svn更新就容易发生树冲突“Tree Confilict”.会出现类似提示。 local unversioned, incoming add upon update1local unversioned,incoming add upon update如果使用图形化客户端可以通过对比文件和解决冲突按钮进行解决&#xff0c; 如果是使用…

c++ vector学习

参考资料&#xff1a; cppreference.com 本文代码&#xff1a; 本文源码 目录隐式成员函数1.operator &#xff08;赋值给容器&#xff09;2.assign &#xff08;将值赋给容器&#xff09;元素访问3.at &#xff08;访问指定元素&#xff0c;进行下标检查&#xff09;4.operat…

linux关闭声音

对于CentOS/Redhat/RHEL/Fedora系统&#xff0c;使用root身份执行&#xff1a;echo "alias pcspkr off" >> /etc/modprobe.conf转载于:https://www.cnblogs.com/keethebest/p/3434821.html

Bundle Identifier

Bundle Identifier : 产品的唯一标识符 1.在模拟器上面&#xff0c;只能有一个唯一的标识符的应用程序 2.在AppStore上&#xff0c;所有的应用程序的Bundler ID都是唯一的 Bundle ID 公司的反向域名 产品名 Bundle ID 不支持中文&#xff0c;因此如果是上架产品&#xff0c;需…

c++ array学习

参考资料&#xff1a; cppreference.com 本文代码&#xff1a; 本文源码 array和vector的区别是array是和C中的数组类似&#xff0c;不能动态改变数组大小&#xff0c;所以会比vector少很多函数。 目录隐式定义的成员函数1.operator &#xff08;将另一个容器拷贝过来&#x…

lucene4入门(2)搜索

欢迎转载http://www.cnblogs.com/shizhongtao/p/3440479.html 接着上一篇&#xff0c;这里继续搜索&#xff0c;对于搜索和创建一样&#xff0c;首先你要确定搜索位置&#xff0c;然后用规定的类来读取。还要注意一点&#xff0c;确定分词器&#xff0c;因为不同的分词器所创建…

Topcoder SRM 648 (div.2)

第一次做TC全部通过&#xff0c;截图纪念一下。 终于蓝了一次&#xff0c;也是TC上第一次变成蓝名&#xff0c;下次就要做Div.1了&#xff0c;希望div1不要挂零。。。_(:зゝ∠)_ A. KitayutaMart2 万年不变的水题。 #include<cstdio> #include<cstring> #include&…

Kadane's algorithm学习

Kadane’s algorithm 简单来说就是用来计算数组中的连续子数组之和最大是多少 vector<int> vec; int temp 0,ans 0; for(int i0;i<vec.size();i){temp max(tempvec[i],vec[i]);ans max(temp,ans); } return ans;循环的第一行就是用来比较当前位置的值和前面数组…

好用的ajax后台框架

dwz 简单实用的国产jquery Ui框架 http://www.j-ui.com/#_blank转载于:https://www.cnblogs.com/userbibi/p/3441382.html

OpenFire源码学习之十九:在openfire中使用redis插件(上)

Redis插件 介绍 Redis是目前比较流行的NO-SQL&#xff0c;基于K,V的数据库系统。关于它的相关操作信息&#xff0c;本人这里就不做重复了&#xff0c;相关资料可以看这个网站http://www.redis.io/(官网)、http://www.redis.cn/(中文站)。 这里本人想说的是&#xff0c;拿Redis做…

c++ queue学习

参考资料&#xff1a; cppreference.com 本文代码&#xff1a; 本文源码 目录成员函数1.operator &#xff08;赋值给容器&#xff09;元素访问2.front &#xff08;访问第一个元素&#xff09;3.back &#xff08;访问最后一个元素&#xff09;容量4.empty &#xff08;判断容…

没有文件扩展“.js”的脚本引擎问题解决

安装MinGW的时候提示没有文件扩展“.js”的脚本引擎。原因&#xff1a;系统安装Dreamwear、UltraEdit、EditPlus后修改了.js文件的默认打开方式。当想直接执行js脚本时就会出现此错误。解决办法&#xff1a;打开注册表编辑器&#xff0c;定位[HKEY_CLASSES_ROOT.js]这一项&…

160 - 54 eKH

环境&#xff1a;windows xp 工具&#xff1a; 1、OllyDBG 2、IDA 3、exeinfo 查壳发现是程序无壳且用Delphi语言编写 可以通过搜索字符串的方式定位关键函数地址 这里定位到是 00427B44ReadInput(a2, &v17); // 读取输入的usernameif ( StrL…