顺德定制网站建设,网站模板工具,wordpress 导航栏 搜索,珠海网站建设找哪家本文学习相关资料#xff1a; C/C socket编程教程
环境#xff1a;vs2015 源码#xff1a;本文代码
前面学到了TCP怎么循环发包#xff0c;但是TCP连接的话会出现一个问题粘包。
TCP连接接收到的数据并不是马上读取到内存里面的#xff0c;而是放在缓冲区#xff0c;让…本文学习相关资料 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);