C++中用Socket实现对结构体、长字符串和图片的传输
来源:互联网 发布:程序员老黄历源码 编辑:程序博客网 时间:2024/05/09 03:36
首先说明下,本文的Socket传输引用了CBlockingSocket封装类
这个类比较特殊的是Send和Receive的最后一个参数是超时时间,其它与C库里的类似
首先说结构体吧,这里传输的结构体含有八个整型,如下
typedef struct exceptiontypecount{ int img_num; int ptz_num; int preset_num; int video_num; int device_num; int total_num; int total_channel; int useless; }ExceptionCount,*pExceptionCount;
关于Socket的创建和连接这里就不说了,参见点击打开链接
这里只说下收发部分的实现
服务端:
memset(counttemp,0,256);//清空缓存 memcpy(counttemp,&ExCount,sizeof(ExCount));//将结构体转为字符串 int countlen = sockCon.Send(counttemp,256,1000);
其中,char countemp[256], ExCount是实例化的结构体。
客户端:
memset(countbuff,0,256); int len = sClient.Receive(countbuff,256,1000); // 接受故障数据memset( &count,0,sizeof(count));memcpy( &count, countbuff, sizeof(count) );
这里的count即为输出的结构体,countbuff同样也是个char[256]。
memset这一步非常重要,如果没有预先清空缓存,就容易出现乱码。
==================================================================================================
字符串:
要传一个500K左右的string字符串,肯定不能直接传,因为Socket传输是有字节上限的,好像是16000+字节
所以我们采用分段传输的策略
服务端:
sockCon.Send(allSize,allNum.GetLength(),100);if(!(sockCon.Receive(resbuff,2,10))){ printf("数据量信息发送失败\n"); return ;}else printf("数据量信息发送成功\n"); temp = AllExDataPtr; BytesSent = 0; while(BytesSent<AllExDataSize)//分段传输数据 { int BytesSentThisTime=sockCon.Send(temp,((AllExDataSize-BytesSent)<256)?(AllExDataSize-BytesSent):256,1000); BytesSent = BytesSent + BytesSentThisTime; temp = temp + BytesSentThisTime; }
其中,AllExDataPtr是指向需要传输的string的一个char*指针,定义为:AllExDataPtr = (char*) AllExData.c_str();
AllSize就是这段数据的字节数,需要首先传到客户端,客户端才可以正常接收
客户端:
int sizelen = sClient.Receive(sizebuff,10,50);//接受数据大小if(sizelen !=0){char flag[]="1";sClient.Send(flag,2,10);}sizebuff[sizelen]='\0';exsize = atoi(sizebuff);printf("数据大小:%d\n",exsize);extemp = new char[exsize+256];//初始化存储信息的数据,留出冗余空间,以防溢出exdata = extemp;//新建指针指向起始地址,方便接收后调用int BytesReceivedThisTime = 0;while(BytesReceived < exsize){BytesReceivedThisTime = sClient.Receive(temp,256,1000);strcpy(extemp,temp);BytesReceived = BytesReceived + BytesReceivedThisTime;extemp = extemp + BytesReceivedThisTime;} std::string out = exdata;
其中out即为要输出的string,这里建了两个指针指向新建的char数组,其中extemp用于接收时的迭代,exdata用于调用该数组
================================================================================================
图片:
要实现的就是收发图片,这里只写客户端发服务端收的例子,其他均类似
客户端:
int ImageSocketClient::UploadFileBySocket(std::string filename, int type){CFileFind Finder;//确保本地有该文件if (!Finder.FindFile(filename.c_str())){return -1;//文件未找到}char inbuff[2];sockType = SOCKET_UPLOAD; //上传操作标志位CString str; //将整形标志位转成字符型str.Format("%d", sockType);char* flag = str.GetBuffer(0);if(!m_bConnectOK) //如果Socket没有连接{ try{CSockAddr saClient(m_strSocketAddress,5858);//设IP和端口m_SocketClient.Create();//创建套接字m_SocketClient.Connect(saClient);//发起连接m_SocketClient.Send(flag,str.GetLength(),4); // 发送上传标识符int len=m_SocketClient.Receive(inbuff,2,4);if(len == 0)return 0;elsem_bConnectOK = TRUE; //连接成功}catch (CBlockingSocketException* e){delete(e);return 0;}}else{try{m_SocketClient.Send(flag,str.GetLength(),4); // 发送上传标识符int len=m_SocketClient.Receive(inbuff,2,4);if(len == 0)return 0;}catch (CBlockingSocketException* e){delete(e);return 0;}}// 获取本地路径char szPath[MAX_PATH];GetCurrentDirectory(MAX_PATH, szPath);CString strpath(szPath);int idx = strpath.ReverseFind(_T('\\'));if( idx != strpath.GetLength()-1)//如果最后一个字符不是\(非根目录),则添加\。{strpath = strpath+"\\";}//设置本地路径+文件名CString strLocalFile;strLocalFile.Format("%s%s",strpath,filename.c_str()); CString strRemoteFile;//服务器保存路径switch (type){case 1:strRemoteFile.Format("\\Preset\\%s",filename.c_str());break;case 2:strRemoteFile.Format("\\IMG_Exception\\%s",filename.c_str());break;case 3:strRemoteFile.Format("\\PTZ_Exception\\%s",filename.c_str());break;case 4:strRemoteFile.Format("\\PRESET_Exception\\%s",filename.c_str());break;default:strRemoteFile = filename.c_str();break;}//发送服务器保存路径,方便后续存储try{char inbuff[2];char * buf = strRemoteFile.GetBuffer(0);m_SocketClient.Send(buf,MAX_PATH,5);int len = m_SocketClient.Receive(inbuff,2,5);if(len == 0)return 0; //发送失败}catch (CBlockingSocketException* e){delete(e);return 0;}FILE * fstream = fopen(strLocalFile,"rb"); // 读取文件数据if ( NULL == fstream ){printf( "打开文件失败,错误码:%d", GetLastError() );return 0;}int nNumRead = 0;char temp[256];if(NULL != fstream){WaitForSingleObject(m_hMutex,MutexTime_ImageSocket);printf("开始上传\n");while( !feof( fstream ) )//未到文件末尾,则继续发送{nNumRead = fread( temp, 1, 256, fstream );m_SocketClient.Send( temp, nNumRead, 500 );}printf("上传成功\n");fclose( fstream );ReleaseMutex(m_hMutex);}m_SocketClient.Close();m_SocketClient.Cleanup();return 1;}
这里首先传操作标识符,让服务器准备好接收图片,
然后根据文件名和类型确定服务端的图片存储路径,并传给服务端
然后再分段存储图片
服务端:
int ReceiveImage(CBlockingSocket& sockCon){char szPath[MAX_PATH];//获取本地路径GetCurrentDirectory(MAX_PATH, szPath);CString strpath(szPath);// 获取客户端传来的存储路径char pathtemp[MAX_PATH];int len = sockCon.Receive( pathtemp,MAX_PATH,5 );if(len == 0)return 0;else // 若获取成功则返回成功标志位{char sucflag[2] = "1";sockCon.Send(sucflag,2,5);}CString filepath(pathtemp);//设置存储文件路径CString strSaveFile;strSaveFile.Format("%s%s",strpath,filepath);printf("存储路径:%s\n",strSaveFile);CFileFind Finder;//确保本地没有该文件if (Finder.FindFile(strSaveFile)){DeleteFile(strSaveFile);}WaitForSingleObject(m_hMutex,MutexTime_ImageSocket);FILE * fstream = fopen(strSaveFile, "wb" );//打开文件操作if ( NULL == fstream ){return 0;}//分段接受并存储文件char temp[256];int nNumRead = 0;printf("开始接收图片\n");while( true ){nNumRead = sockCon.Receive(temp,256,500);//文件分段接收if ( 0 == nNumRead )//若仍有数据,则持续接受break;fwrite( temp, 1, nNumRead, fstream );}ReleaseMutex(m_hMutex);printf("图片接收成功\n");fclose( fstream );return 1;}
最后我再说几条在用CBlockingSocket封装类需要注意的几点
1. 由于Send和Receive函数最后的参数是超时时间,所以在传输大文件时,尽量将其设得高点,我在传输大图片时就遇到过超时而只传一半的情况。
2. 若客户端和服务端有多次Send和Receive交互,对应的Send和Receive之间的接受字节大小(即第二个参数)一定要对应。
3. 在连续两个Send或Receive时一定要注意发送方和接收方的字节长度,若有偏差则很可能会将Send的字符串分割到两个Receive中去。
4. 全局变量指针在新开的线程中无法调用,报错为Bad Ptr,只能在线程中定义新指针。
- C++中用Socket实现对结构体、长字符串和图片的传输
- C++中用Socket实现对结构体、长字符串和图片的传输
- linux下c语言实现图片的socket传输和数据库的存储
- linux下c语言实现图片的socket传输和数据库的存储
- c#socket实现对序列化对象的传输和接收
- Linux C socket传输结构体
- Linux socket 传输和接受结构体
- Java使用Socket进行字符串和图片文件同时传输
- C#.NET通过Socket实现平行主机之间网络通讯(含图片传输的Demo演示)
- 使用base64实现socket.io传输图片和声音文件
- 结构体中用字符串排序的sort自定义函数和 结构体的操作
- 谈Socket传输结构体
- C++ socket传输结构体
- 已解决:Linux中用socket实现视频、音频的同步传输
- BLE传输字符串和传输图片
- 在c语言中用正则表达式实现对email地址和ip地址的验证
- windows和Linux之间socket传输结构体关于字节对齐产生的问题
- Java 与 C socket通信传输结构体消息/Java解析C语言结构体
- 讲述一个三流本科生的世界
- Steve Jobs于2005年在斯坦福大学毕业典礼上的演讲
- D
- Android导入一个工程时提示 Invalid project description
- CPU流水线的探秘之旅
- C++中用Socket实现对结构体、长字符串和图片的传输
- 异常——排除表达式的异常
- tomcat 中设置连接池
- MPLS 初学者的常见问题
- android学习笔记之自制简易浏览器
- 无法绑定由多个部分组成的标识符--解决办法
- Python发送HTTP GET请求
- C++ primer 统计单词个数
- 计算机图形学的学习