MFC开发IM---MFC实现http协议传输图片和文本
要将自己的文件通过http协议进行上传到Web服务器,就必须进行数据封装,也就是加上http协议的包头,数据前加上数据信息描述,协议尾三部分,一边服务端进行解析。在我们本次项目中,我需要控制Ip摄像头进行拍照,将抓取的图片通过Http协议传送到另一个人负责的服务器端。我用的的时MFC,完成控制客户端开发。
首先他给了我他要求的包头,数据描述,结尾符格式,让我按找C++来实现。首先贴出他的Java封装代码:
给的Java格式封装,要求进行C++仿写:
public class SocketHttpRequester {
/**
* 直接通过HTTP协议提交数据到服务器,实现如下面表单提交功能:
* <FORM METHOD=POST ACTION="http://192.168.1.101:8083/upload/servlet/UploadServlet" enctype="multipart/form-data">
<INPUT TYPE="text" NAME="name">
<INPUT TYPE="text" NAME="id">
<input type="file" name="imagefile"/>
<input type="file" name="zip"/>
</FORM>
* @param path 上传路径(注:避免使用localhost或127.0.0.1这样的路径测试,因为它会指向手机模拟器,你可以使用http://www.iteye.cn或http://192.168.1.101:8083这样的路径测试)
* @param params 请求参数 key为参数名,value为参数值
* @param file 上传文件
*/
public static String post(String path, Map<String, String> params, FormFile[] files) throws Exception{
final String BOUNDARY = "---------------------------7da2137580612"; //数据分隔线
final String endline = "--" + BOUNDARY + "--\r\n";//数据结束标志
int fileDataLength = 0;
if (files!=null||files.length>0) {
for(FormFile uploadFile : files){//得到文件类型数据的总长度
StringBuilder fileExplain = new StringBuilder();
fileExplain.append("--");
fileExplain.append(BOUNDARY);
fileExplain.append("\r\n");
fileExplain.append("Content-Disposition: form-data;name=\""+ uploadFile.getParameterName()+"\";filename=\""+ uploadFile.getFilname() + "\"\r\n");
fileExplain.append("Content-Type: "+ uploadFile.getContentType()+"\r\n\r\n");
fileExplain.append("\r\n");
fileDataLength += fileExplain.length();
if(uploadFile.getInStream()!=null){
fileDataLength += uploadFile.getFile().length();
}else{
fileDataLength += uploadFile.getData().length;
}
}
}
StringBuilder textEntity = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {//构造文本类型参数的实体数据
textEntity.append("--");
textEntity.append(BOUNDARY);
textEntity.append("\r\n");
textEntity.append("Content-Disposition: form-data; name=\""+ entry.getKey() + "\"\r\n\r\n");
textEntity.append(entry.getValue());
textEntity.append("\r\n");
}
//计算传输给服务器的实体数据总长度
int dataLength = textEntity.toString().getBytes().length + fileDataLength + endline.getBytes().length;
URL url = new URL(path);
int port = url.getPort()==-1 ? 80 : url.getPort();
Socket socket = new Socket(InetAddress.getByName(url.getHost()), port);
OutputStream outStream = socket.getOutputStream();
//下面完成HTTP请求头的发送
String requestmethod = "POST "+ url.getPath()+" HTTP/1.1\r\n";
outStream.write(requestmethod.getBytes());
String accept = "Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*\r\n";
outStream.write(accept.getBytes());
String language = "Accept-Language: zh-CN\r\n";
outStream.write(language.getBytes());
String contenttype = "Content-Type: multipart/form-data; boundary="+ BOUNDARY+ "\r\n";
outStream.write(contenttype.getBytes());
String contentlength = "Content-Length: "+ dataLength + "\r\n";
outStream.write(contentlength.getBytes());
String alive = "Connection: Keep-Alive\r\n";
outStream.write(alive.getBytes());
String host = "Host: "+ url.getHost() +":"+ port +"\r\n";
outStream.write(host.getBytes());
//写完HTTP请求头后根据HTTP协议再写一个回车换行
outStream.write("\r\n".getBytes());
//把所有文本类型的实体数据发送出来
outStream.write(textEntity.toString().getBytes());
//把所有文件类型的实体数据发送出来
for(FormFile uploadFile : files){
StringBuilder fileEntity = new StringBuilder();
fileEntity.append("--");
fileEntity.append(BOUNDARY);
fileEntity.append("\r\n");
fileEntity.append("Content-Disposition: form-data;name=\""+ uploadFile.getParameterName()+"\";filename=\""+ uploadFile.getFilname() + "\"\r\n");
fileEntity.append("Content-Type: "+ uploadFile.getContentType()+"\r\n\r\n");
outStream.write(fileEntity.toString().getBytes());
if(uploadFile.getInStream()!=null){
byte[] buffer = new byte[1024];
int len = 0;
while((len = uploadFile.getInStream().read(buffer, 0, 1024))!=-1){
outStream.write(buffer, 0, len);
}
uploadFile.getInStream().close();
}else{
outStream.write(uploadFile.getData(), 0, uploadFile.getData().length);
}
outStream.write("\r\n".getBytes());
}
//下面发送数据结束标志,表示数据已经结束
outStream.write(endline.getBytes());
进行的进行C++格式封装如下:
1.请求包头处理:
CString CHotpimUploadDlg::MakeRequestHeaders(CString &strBoundary)//包头
{
CString strFormat;
CString strData;
CString accept = _T("Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*\r\n");
CString language = _T("Accept-Language: zh-CN\r\n");
CString contenttype = _T("Content-Type: multipart/form-data; boundary=%s\r\n");//二进制文件传送Content-Type类型为: multipart/form-data
CString contentlength = _T("Content-Length: %d\r\n");
CString alive = _T("Connection: Keep-Alive\r\n");
CString host = _T("Host: 192.168.1.112:8080\r\n");
CString anotherEnter = _T("\r\n");
/* 经过多次尝试发现一开头必须为contenttype,只要这一串字符在开头都可以实现图片上传Web服务器
下面的三种字符排列格式,后两种都可行都是可行的,可根据实际情况添加*/
//strFormat += accept+language+contenttype+contentlength+alive+host+anotherEnter;
//strFormat = contenttype;//这行必须要它标志数据开始,其他包头可根据实际添加
strFormat += contenttype+accept+language+contenttype+contentlength+alive+host+anotherEnter;
//strData.Format(strFormat, strBoundary,m_HeaderStrLen);
strData.Format(strFormat, strBoundary,strBoundary, m_HeaderStrLen);// m_HeaderStrLen = strlen(strPreFileData+endLine);
//strData.Format(strFormat, strBoundary);
return strData;
}
2.传输数据描述:
{
CString strFormat;
CString strData;
/* 前面的是需要给服务器的一些参数信息,
strFormat += _T("--%s");
strFormat += _T("\r\n");
strFormat += _T("Content-Disposition: form-data; name=\"identitynumber\"");
strFormat += _T("\r\n\r\n");
strFormat += _T("141040046");//id值
strFormat += _T("\r\n");
//
strFormat += _T("--%s");
strFormat += _T("\r\n");
strFormat += _T("Content-Disposition: form-data; name=\"time\"");
strFormat += _T("\r\n\r\n");
strFormat += _T("1433323280446");//时间值
strFormat += _T("\r\n");
///需要传输的图片文件//
strFormat += _T("--%s");
strFormat += _T("\r\n");
strFormat += _T("Content-Disposition: form-data;name=\"image\";filename=\"%s\"");
strFormat += _T("\r\n");
strFormat += _T("Content-Type: application/octet-stream\r\n\r\n");
strData.Format(strFormat, strBoundary, strBoundary, strBoundary, strFileName);
//m_strLen = strlen(strData);
return strData;
}
3.数据尾部部分:
{
CString strFormat;
CString strData;
/* 提交完成,根据服务器端实际情况添加,我们的服务器端只需要有结尾标示符就好
strFormat = _T("\r\n");
strFormat += _T("--%s");
strFormat += _T("\r\n");
strFormat += _T("Content-Disposition: form-data; name=\"submitted\"");
strFormat += _T("\r\n\r\n");
strFormat += _T("submit");
*/
/* 结尾标示符endLine = "--strBoundary--" */
strFormat += _T("\r\n");
strFormat += _T("--%s--");
strFormat += _T("\r\n");
//strData.Format(strFormat, strBoundary, strBoundary);
strData.Format(strFormat, strBoundary);
return strData;
}
4.数据发送过程如下:
{
CString _mFilePath;
//_mFilePath = "E:\\1.dat";//要传的本地文件地址
//_mFilePath = "E:\\1.pdf";
mFilePath = "E:\\20150602194621.jpg";
int startp = _mFilePath.ReverseFind('\\');
int namelen = _mFilePath.GetLength()-startp-1;
CString pcmname = _mFilePath.Mid(startp+1,namelen);
CString defServerName ="192.168.1.103";//服务器名
CString defObjectName ="/ShcoolSafer/ArriveMessageAction";//保存的地址
// USES_CONVERSION;
CInternetSession Session;
CHttpConnection *pHttpConnection = NULL;
INTERNET_PORT nPort = 80;
CFile fTrack;
CHttpFile* pHTTP;
CString strRequestHeader;
CString strBoundary ;
CString strPreFileData ;
CString strPostFileData ;
DWORD dwTotalRequestLength;
DWORD dwChunkLength;
DWORD dwReadLength;
DWORD dwResponseLength;
TCHAR szError[MAX_PATH];
void* pBuffer = NULL;
LPSTR szResponse;
CString strResponse;
BOOL bSuccess = TRUE;
CString strDebugMessage = _T("");
if (FALSE == fTrack.Open(_mFilePath, CFile::modeRead | CFile::shareDenyWrite))//读出文件
{
AfxMessageBox(_T("Unable to open the file."));
return FALSE;
}
int iRecordID = 1;
strBoundary = _T("---------------------------7da2137580612");//定义边界值
CString endLine = _T("-----------------------------7da2137580612--\r\n");//结尾符
strPreFileData = MakePreFileData(strBoundary, pcmname, iRecordID);
m_HeaderStrLen = strlen(strPreFileData+endLine);
strRequestHeader = MakeRequestHeaders(strBoundary);
strPostFileData = MakePostFileData(strBoundary);
dwTotalRequestLength = strPreFileData.GetLength() + strPostFileData.GetLength() + fTrack.GetLength();//计算整个包的总长度
//
dwChunkLength = fTrack.GetLength();
pBuffer = malloc(dwChunkLength);
if (NULL == pBuffer)
{
return FALSE;
}
try
{
pHttpConnection = Session.GetHttpConnection(defServerName,nPort);
pHTTP = pHttpConnection->OpenRequest(CHttpConnection::HTTP_VERB_POST, defObjectName);
pHTTP->AddRequestHeaders(strRequestHeader);//发送包头请求
pHTTP->SendRequestEx(dwTotalRequestLength, HSR_SYNC | HSR_INITIATE);
#ifdef _UNICODE
pHTTP->Write(W2A(strPreFileData), strPreFileData.GetLength());
#else
pHTTP->Write((LPSTR)(LPCSTR)strPreFileData, strPreFileData.GetLength());//写入服务器所需信息
#endif
dwReadLength = -1;
while (0 != dwReadLength)
{
strDebugMessage.Format(_T("%u / %u\n"), fTrack.GetPosition(), fTrack.GetLength());
TRACE(strDebugMessage);
dwReadLength = fTrack.Read(pBuffer, dwChunkLength);//文件内容
if (0 != dwReadLength)
{
pHTTP->Write(pBuffer, dwReadLength);//写入服务器本地文件,用二进制进行传送
}
}
#ifdef _UNICODE
pHTTP->Write(W2A(strPostFileData), strPostFileData.GetLength());
#else
pHTTP->Write((LPSTR)(LPCSTR)strPostFileData, strPostFileData.GetLength());
#endif
pHTTP->EndRequest(HSR_SYNC);
dwResponseLength = pHTTP->GetLength();
while (0 != dwResponseLength)
{
szResponse = (LPSTR)malloc(dwResponseLength + 1);
szResponse[dwResponseLength] = '\0';
pHTTP->Read(szResponse, dwResponseLength);
strResponse += szResponse;
free(szResponse);
dwResponseLength = pHTTP->GetLength();
}
}
catch (CException* e)
{
e->GetErrorMessage(szError, MAX_PATH);
e->Delete();
AfxMessageBox(szError);
bSuccess = FALSE;
}
pHTTP->Close();
delete pHTTP;
fTrack.Close();
if (NULL != pBuffer)
{
free(pBuffer);
}
return bSuccess;
}
5.发送图片时,截取的数据如下(文本显示):
MFC开发IM---MFC实现http协议传输图片和文本相关推荐
- 【Visual Studio 2019】创建 MFC 桌面程序 ( 安装 MFC 开发组件 | 创建 MFC 应用 | MFC 应用窗口编辑 | 为按钮添加点击事件 | 修改按钮文字 | 打开应用 )
文章目录 一.安装 MFC 开发组件 二.创建 MFC 应用 三.MFC 应用窗口编辑 四.为按钮添加点击事件 五.修改按钮文字 六.打开系统其它应用 七.博客源码 一.安装 MFC 开发组件 打开 ...
- VC用MFC开发的圆形进度条控件
DownLoad Src VC用MFC开发的圆形进度条控件 visualsan@yahoo.cn NUAA zss 在NBA2007游戏里,还有很多科幻电影里,经常可以看到圆形进度条.有的用来显示导弹 ...
- 使用MFC开发ActiveX控件
摘要: 本文对COM组件中的ActiveX控件的MFC开发方法进行了介绍,讲述了用户自定义和库存属性.方法以及事件的添加方法和属性页的制作过程.使读者能够掌握基本的MFC ActiveX开发方法. 前 ...
- 随想录(MFC开发有感)
[ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 虽然之前也写过一些mfc的文章,但是时间长了也会忘了.对于很多同学来说,用C#开发图形界面又快又 ...
- QT开发和MFC开发的经典案例
大家来欣赏下Qt写的程序(摘自百度百科) 3DSlicer, a free open source software for visualization and medical image co ...
- MFC开发——卡拉OK字幕制作
依然是为了赶老师作业,又去学了点东西,然后做了个小项目.首先在开始做项目之前,说一下整体思路,要实现卡拉OK字幕效果,就要对文本类与定时器有一定的掌握,通过定时器的更新,可以实现字体颜色的变化,与字幕 ...
- VS2005下MFC开发的ActiveX控件的部分总结 inf 篇
本博客转载CSDN网友http://blog.csdn.net/immc1979/archive/2007/04/20/1572222.aspx,本人觉得写得非常的实在,一看就是从实际经验中总结出来的 ...
- snap7-c++/MFC开发笔记
snap7-c++/MFC开发笔记 书接上文,通过对python-snap7的库的研究,笔者掌握了上位机与plc通讯的基本原理与方法,然工业现场上位机的用户界面基本上是以c++为底层语言制作的,pyt ...
- NX二次开发-使用MFC的CImage裁剪图片
NX二次开发-使用MFC的CImage裁剪图片 示例: 这里有一张美女的照片,我现在想把她的大长腿从这张图片中裁剪出来,然后另存张新的图片. 这个与NX二次开发其实没有太大的关系,主要是用到了MFC里 ...
最新文章
- 新型智能头盔可快速评估患者中风的大小、位置和类型
- 基于JavaEE实现网上拍卖系统
- Google实用搜索秘技六则
- PLS-00172: string literal too long
- 页目录项和页表项——《x86汇编语言:从实模式到保护模式》读书笔记43
- CentOS忘记普通用户密码解决办法
- linux 双网卡 debian,Debian 双网卡bond
- 作者:胡良霖(1973-),男,中国科学院计算机网络信息中心高级工程师
- 20155201 实验四《Java面向对象程序设计》实验报告
- ReactMotion Demo8 分析
- 各种激活破解工具一览
- 微信支付“下单账号和支付账号不一致,请核实后再支付”
- 257套工业机器人SW设计3D图纸 焊接机械手/发那科ABB安川臂模型
- 无限城app为什么服务器繁忙,无限城决战中上弦鬼为何一点忙都帮不上?无惨:全是混子...
- 201掘安杯网络安全赛web的write up
- HR员工管理的三重境界:管事、管人、管心
- TorchDrug教程--逆合成
- vlc tv版 记住网络流_如何使用VLC在Apple TV上播放任何视频
- linux显卡驱动安全模式,大神设置win7在安全模式安装显卡驱动详细的教程?
- System32下几乎所有文件的简单说明