本文学习相关资料:
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);

c++ socket学习(1.4)相关推荐

  1. Android socket 学习记录 之 执行new socket(ip, port)程序崩溃

    这段时间在学习Android的socket编程,我不是专做APP的,做的是bootloader.驱动.hal.framework这个线的,也就是系统搭建和功能优化设计.为了打通这整条线,为此学习了不少 ...

  2. c++ socket学习(1.6)

    本文学习相关资料: C/C++ socket编程教程 环境:vs2015 源码:本文代码 这次来看看UDP 之前在c++ socket学习(1.2)讲过UDP怎么发送了,那现在来做一个可以一直发送的. ...

  3. c++ socket学习(1.3)

    本文学习相关资料: C/C++ socket编程教程 环境:vs2015 源码:本文代码 在这里c++ socket学习(1.1)学到了怎么样建立TCP,然后通过TCP连接发送.接收信息. 但是都是一 ...

  4. Android基础入门教程——7.6.1 Socket学习网络基础准备

    Android基础入门教程--7.6.1 Socket学习网络基础准备 标签(空格分隔): Android基础入门教程 本节引言: 为了照顾没学过Java Socket的初学者,或者说捋一捋Andro ...

  5. Linux Socket学习(十三)

    使用UDP进行广播 如果通信只能在两个单体之间完成,这样的方式是没有效率的.另一方面,广播允许同时要多个接收者传播信息. 在这一章,我们将会学习下列内容: 建立一个UDP广播套接口 使用套接口发送广播 ...

  6. Linux Socket学习(十八)--完

    一个实际的网络工程 不论我们的头脑是否在由上一章的学习中清醒过来,现在我们需要休息一下了.在这一章我们并不讨论新的内容,而是用我们所学到的这些东西来实现一些有趣的事情.在学习了这么多的东西之后来一些有 ...

  7. c++ socket学习(1.5)

    本文学习相关资料: C/C++ socket编程教程 环境:vs2015 源码:本文代码 这次来试一下使用TCP来传输文件,其实传输数据和差不多,就是多一个读取文件,和一个写文件而已. 服务端 int ...

  8. c++ socket学习(1.2)

    本文学习相关资料: C/C++ socket编程教程 环境:vs2015 源码:本文代码 windows 如何创建客户端与服务端通信? UDP: 这次就没什么客户端服务端好说了,UDP是没有无连接的 ...

  9. c++ socket学习(1.1)

    本文学习相关资料: C/C++ socket编程教程 环境:vs2015 源码:本文代码 windows 如何创建客户端与服务端通信? TCP: 服务端 在windows先告诉程序我们要使用哪个版本的 ...

最新文章

  1. mysql构建url给scrapy_Python Scrapy从mysq填充起始url
  2. 天翼云从业认证(4.1)上云迁移实战
  3. python 出现 AttributeError: matplotlib‘ object has no attribute ‘to_rgba‘
  4. PHP 算法之 -- 计算器设计
  5. mysql 压缩版安装
  6. python中range 函数_pythonrange,range函数的用法
  7. 物体运动到一个点停止_大颗粒搭建中常见的结构运动
  8. 把Faster-RCNN的原理和实现阐述得非常清楚
  9. 关于Win32 DialogBox的一些收获
  10. vue用户行为收集_Vue前端数据采集 埋点 追踪用户系列行为
  11. lede固件_开源路由器固件OPENWRT/LEDE出现远程代码执行漏洞请尽快升级
  12. 中职学校计算机基础设施建设,以信息化推动中职学校计算机专业建设.doc
  13. 南京工程学院计算机博士,南京工程学院高层次人才引进工作实施办法(修订)...
  14. gdi与gdi+绘图效率_.NET和GDI +进行绘图[第1部分:基础知识]
  15. mysql主从延迟时间是多少_MySQL主从同步个般是多久的延迟?
  16. 【计算机网络】数据链路层 : 以太网 ( 无连接、不可靠服务 | 以太网发展 | 10BASE-T 以太网 | MAC 地址 | 以太网 MAC 帧 | 高速以太网 )
  17. java中像scanf一样多个输入_VB模拟键盘输入的N种方法
  18. P2905 [USACO08OPEN]农场危机Crisis on the Farm-dp
  19. thinkphp实现邮箱发送
  20. 【转载】一封写给有忧国忧民症状的幼稚知识分子的信

热门文章

  1. 值得一谈的鸿蒙2.0,程序员们拿起你们手中的编译器撸一下hello world
  2. android读取excel文件_python里读写excel等数据文件的几种常用方式
  3. httpHandlers和httpModules接口介绍 (5)
  4. jquery ready方法实现原理
  5. 《H5 移动营销设计指南》 读书笔记整理
  6. 记录一个前端架构的想法
  7. css段落文字(中英文混杂)实现两端对齐
  8. 笔记 — 动画效果(Css3)
  9. 深入css布局 (1) — 盒模型 元素分类
  10. http://www.tldp.org/LDP/abs/abs-guide.txt.gz