C++中用Socket实现对结构体、长字符串和图片的传输首先说明下,本文的Socket传输引用了CBlockingSocket封装类这个类比较特殊的是Send和Receive的最后一个参数是超时时间,其它与C库里的类似首先说结构体吧,这里传输的结构体含有八个整型,如下[cpp]viewplaincopyprint?1.typedefstructexceptiontypecount{2.intimg_num;3.intptz_num;4.intpreset_num;5.intvideo_num;6.intdevice_num;7.inttotal_num;8.inttotal_channel;9.intuseless;10.}ExceptionCount,*pExceptionCount;关于Socket的创建和连接这里就不说了,参见点击打开链接这里只说下收发部分的实现服务端:[cpp]viewplaincopyprint?1.[cpp]viewplaincopyprint?1.memset(counttemp,0,256);//清空缓存2.memcpy(counttemp,&ExCount,sizeof(ExCount));//将结构体转为字符串3.intcountlen=sockCon.Send(counttemp,256,1000);其中,charcountemp[256],ExCount是实例化的结构体。客户端:[cpp]viewplaincopyprint?1.memset(countbuff,0,256);2.intlen=sClient.Receive(countbuff,256,1000);//接受故障数据3.memset(&count,0,sizeof(count));4.memcpy(&count,countbuff,sizeof(count));这里的count即为输出的结构体,countbuff同样也是个char[256]。memset这一步非常重要,如果没有预先清空缓存,就容易出现乱码。==================================================================================================字符串:要传一个500K左右的string字符串,肯定不能直接传,因为Socket传输是有字节上限的,好像是16000+字节所以我们采用分段传输的策略服务端:[cpp]viewplaincopyprint?1.sockCon.Send(allSize,allNum.GetLength(),100);2.if(!(sockCon.Receive(resbuff,2,10)))3.{4.printf(数据量信息发送失败\n);5.return;6.}7.else8.printf(数据量信息发送成功\n);9.10.11.temp=AllExDataPtr;12.BytesSent=0;13.while(BytesSentAllExDataSize)//分段传输数据14.{15.intBytesSentThisTime=sockCon.Send(temp,((AllExDataSize-BytesSent)256)?(AllExDataSize-BytesSent):256,1000);16.BytesSent=BytesSent+BytesSentThisTime;17.temp=temp+BytesSentThisTime;18.}其中,AllExDataPtr是指向需要传输的string的一个char*指针,定义为:AllExDataPtr=(char*)AllExData.c_str();AllSize就是这段数据的字节数,需要首先传到客户端,客户端才可以正常接收客户端:[cpp]viewplaincopyprint?1.intsizelen=sClient.Receive(sizebuff,10,50);//接受数据大小2.if(sizelen!=0)3.{4.charflag[]=1;5.sClient.Send(flag,2,10);6.}7.sizebuff[sizelen]='\0';8.exsize=atoi(sizebuff);9.printf(数据大小:%d\n,exsize);10.extemp=newchar[exsize+256];//初始化存储信息的数据,留出冗余空间,以防溢出11.exdata=extemp;//新建指针指向起始地址,方便接收后调用12.13.intBytesReceivedThisTime=0;14.while(BytesReceivedexsize)15.{16.BytesReceivedThisTime=sClient.Receive(temp,256,1000);17.strcpy(extemp,temp);18.BytesReceived=BytesReceived+BytesReceivedThisTime;19.extemp=extemp+BytesReceivedThisTime;20.}21.std::stringout=exdata;其中out即为要输出的string,这里建了两个指针指向新建的char数组,其中extemp用于接收时的迭代,exdata用于调用该数组================================================================================================图片:要实现的就是收发图片,这里只写客户端发服务端收的例子,其他均类似客户端:[cpp]viewplaincopyprint?1.intImageSocketClient::UploadFileBySocket(std::stringfilename,inttype)2.{3.CFileFindFinder;//确保本地有该文件4.if(!Finder.FindFile(filename.c_str()))5.{6.return-1;//文件未找到7.}8.9.charinbuff[2];10.sockType=SOCKET_UPLOAD;//上传操作标志位11.CStringstr;//将整形标志位转成字符型12.str.Format(%d,sockType);13.char*flag=str.GetBuffer(0);14.15.if(!m_bConnectOK)//如果Socket没有连接16.{17.try18.{19.CSockAddrsaClient(m_strSocketAddress,5858);//设IP和端口20.m_SocketClient.Create();21.//创建套接字22.m_SocketClient.Connect(saClient);23.//发起连接24.m_SocketClient.Send(flag,str.GetLength(),4);//发送上传标识符25.intlen=m_SocketClient.Receive(inbuff,2,4);26.if(len==0)27.return0;28.else29.m_bConnectOK=TRUE;//连接成功30.31.}32.catch(CBlockingSocketException*e)33.{34.delete(e);35.return0;36.}37.}38.else39.{40.try41.{42.m_SocketClient.Send(flag,str.GetLength(),4);//发送上传标识符43.intlen=m_SocketClient.Receive(inbuff,2,4);44.if(len==0)45.return0;46.}47.catch(CBlockingSocketException*e)48.{49.delete(e);50.return0;51.}52.}53.54.//获取本地路径55.charszPath[MAX_PATH];56.GetCurrentDirectory(MAX_PATH,szPath);57.CStringstrpath(szPath);58.intidx=strpath.ReverseFind(_T('\\'));59.if(idx!=strpath.GetLength()-1)//如果最后一个字符不是\(非根目录),则添加\。60.{61.strpath=strpath+\\;62.}63.//设置本地路径+文件名64.CStringstrLocalFile;65.strLocalFile.Format(%s%s,strpath,filename.c_str());66.67.CStringstrRemoteFile;68.//服务器保存路径69.switch(type)70.{71.case1:72.strRemoteFile.Format(\\Preset\\%s,filename.c_str());73.break;74.case2:75.strRemoteFile.Format(\\IMG_Exception\\%s,filename.c_str());76.break;77.case3:78.strRemoteFile.Format(\\PTZ_Exception\\%s,filename.c_str());79.break;80.case4:81.strRemoteFile.Format(\\PRESET_Exception\\%s,filename.c_str());82.break;83.default:84.strRemoteFile=filename.c_str();85.break;86.}87.88.//发送服务器保存路径,方便后续存储89.try90.{91.charinbuff[2];92.char*buf=strRemoteFile.GetBuffer(0);93.m_SocketClient.Send(buf,MAX_PATH,5);94.intlen=m_SocketClient.Receive(inbuff,2,5);95.if(len==0)96.return0;//发送失败97.}98.catch(CBlockingSocketException*e)99.{100.delete(e);101.return0;102.}103.104.105.106.FILE*fstream=fopen(strLocalFile,rb);//读取文件数据107.108.if(NULL==fstream)109.{110.printf(打开文件失败,错误码:%d,GetLastError());111.return0;112.}113.114.intnNumRead=0;115.chartemp[256];116.117.if(NULL!=fstream)118.{119.WaitForSingleObject(m_hMutex,MutexTime_ImageSocket);120.printf(开始上传\n);121.while(!feof(fstream))//未到文件末尾,则继续发送122.{123.nNumRead=fread(temp,1,256,fstream);124.m_SocketClient.Send(temp,nNumRead,500);125.}126.printf(上传成功\n);127.fclose(fstream);128.ReleaseMutex(m_hMutex);129.}130.m_SocketClient.Close();131.m_SocketClient.Cleanup();132.return1;133.}这里首先传操作标识符,让服务器准备好接收图片,然后根据文件