(已经经过测试没有问题了!)
服务端发送数据,粘包处理:
int dataLength =xystr.size();
//将数据前四个字节放入数据长度以解决粘包
int realLength = dataLength + sizeof(int);
char *sendData = new char[realLength];
memset(sendData, 0, realLength*sizeof(char));
unsigned int num1, num2, num3, num4;
char *p = (char *)&dataLength;
num1 = ((int)*p);
num2 = ((int)*(p+1));
num3 = ((int)*(p+2));
num4 = ((int)*(p+3));
memcpy(sendData, &num4, sizeof(int));
memcpy(sendData+sizeof(char), &num3, sizeof(int));
memcpy(sendData+2*sizeof(char), &num2, sizeof(int));
memcpy(sendData+3*sizeof(char), &num1, sizeof(int));
memcpy(sendData+sizeof(int), xystr.c_str(), xystr.size());
客户端循环接收数据并处理粘包,解析json,客户端因为没有考虑到包头可能会在recvbuf的后四个字节里或者被分割,导致包头数值不正确,并且第二次取出的recvbuf也需要跳过剩余包头,不然会导致json解析失败,所以又加入了jump变量。处理包头的地方一定要注意细节!!!很容易出错的,并且不容易复现(因为包头恰巧在recvbuf后面四个字节的概率很小)
#include<stdio.h>
#include <sys/socket.h> //connect,send,recv,setsockopt等
#include <sys/types.h>
#include <netinet/in.h> // sockaddr_in, "man 7 ip" ,htons
#include <poll.h> //poll,pollfd
#include <arpa/inet.h> //inet_addr,inet_aton
#include <unistd.h> //read,write
#include <netdb.h> //gethostbyname
#include <error.h> //perror
#include <stdio.h>
#include <errno.h> //errno
#include <string.h> // memset
#include <iostream>
#include<stdlib.h>
#include<boost/foreach.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
using namespace boost::property_tree;
static int count=0;
void json_parase(std::string str)
{
count++;
std::stringstream s1(str);
ptree pt1;
try{
read_json(s1,pt1);
BOOST_FOREACH(boost::property_tree::ptree::value_type &v,pt1)
{
std::stringstream s2;
write_json(s2,v.second);
ptree pt2;
read_json(s2,pt2);
double x=pt2.get<double>("x");
double y=pt2.get<double>("y");
printf("\"X\":%lf,\"Y\":%lf\n",x,y);
}
}
catch(ptree_error &e)
{
return;
}
}
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#define ERR_EXIT(m)\
do\
{\
perror(m);\
exit(EXIT_FAILURE);\
}while(0)
int main(void) {
int sock;
if((sock =socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0)
{
ERR_EXIT("ERROR");
}
struct sockaddr_in servaddr;
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_port = htons(1606);
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
if(connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr))< 0)
{
ERR_EXIT("connect");
}
char sendbuf[1024]={0};
char recvbuf[1024]={0};
int j=0;
char *data=NULL;
char *data1;
int len =0;
int nianbaolen=0;
int jump=0;//假如包头四个字节有的到第二条数据里了,就需要跳过jump个字节
std::string value("");
while(1)
{
if(recv(sock,recvbuf,sizeof(recvbuf),MSG_WAITALL)>0)
{
if(len==0&&nianbaolen==0)
{
char *cint=(char *)&len;
for(int i=4;i>0;i--)
{
(*(cint+i-1))=(int)recvbuf[4-i];
}
for(int i=4;i<1024;i++)
{
value.push_back(recvbuf[i]);
}
memset(recvbuf,0,sizeof(recvbuf));
printf("收到数据包头显示的长度:%d\n",len);
continue;
}else{
if(nianbaolen!=0)
{
printf("nianbaolen:%d\n",nianbaolen);
char *cint=(char *)&len;
jump=0;
for(int i=nianbaolen;i>0;i--)
{
(*(cint +i-1))=(int)recvbuf[jump];
jump++;
}
nianbaolen=0;
printf("粘包头长度:%d\n",len);
}
if(len-value.size()>1024)
{
for(int i=jump;i<1024;i++)
{
value.push_back(recvbuf[i]);
}
jump=0;
memset(recvbuf,0,sizeof(recvbuf));
continue;
}
else{
int i=jump;
while(value.size()!=len)
{
value.push_back(recvbuf[i]);
i++;
}
jump=0;
len=0;
printf("第%d次循环!",count+1);
printf("最终字符串长度:%d\n",value.size());
FILE *fp=fopen("data.txt","w");
fprintf(fp,"%s",value.c_str());
fclose(fp);
json_parase(value);
value="";
if(i<1020)
{
printf("i<1020");
for(int k=0;k<4;k++)
{
char *cint=(char *)&len;
*(cint+k)=(int)recvbuf[i+3-k];
}
i+=4;
while(i<1024)
{
value.push_back(recvbuf[i]);
i++;
}
nianbaolen=0;
printf("粘包包头长度:%d\n",len);
}else{
printf("i不<1020\n\n\n\n\n\n\n\n\n");
nianbaolen=4;
char *cint=(char *)&len;
printf("i的值为:%d\n",i);
while(i<1024)
{
*(cint+nianbaolen-1)=recvbuf[i];
i++;
nianbaolen--;
}
printf("还差%d个字节的包头长度:%d\n",nianbaolen,len);
}
memset(recvbuf,0,sizeof(recvbuf));
}
}
}
}
close(sock);
return 0; }