VC编写自己构造http协议数据的post上传图片类 post数据,是直接在http协议头将Content-Type设为application/x-www-form-urlencoded,这样服务器会将提交的数据,当作表单数据处理。发送的数据格式也为:userid=lilu&data=post图片类&name=天漏客。而post图片则是自己构造http协议数据,将http协议头的Content-Type设为multipart/form-data,同时还要加上 boundary=xxxxxxx(xxxxxxx表示一个字符串),后面的协议数据内容将要以这个xxxxxxx来进行分隔。发送的数据格式为: ---------------2389jhrwfjsjd9823 Content-Disposition: form-data; name="userid" 27EF272F28239E5A34EE223FADFWAFAEaE 类源码、实例源码见文件夹中 首先说一下本类的方便之处。 1、使用方便,步骤简单。 2、发送图片时,还可以构造其他数据。 3、兼容_MBCS和_UNICODE模式,并且能使用GB2312和UTF8两种编码进行发送与接收,类自动实现转换。 首先说一下这个类的使用,方法比较简单。 1、在工程中加入SendData.h和SendData.cpp文件,然后包含头文件,就可以定义类。 CSendData MySend; 2、设置服务器参数。 MySend.SetServerParam(_T(www.lilu.name),_T("/posttest.asp"),80); 3、如果同时要包含数据,就要先构造数据。 MySend.MakePostData(_T("userid"),_T("lilu")); MySend.MakePostData(_T("name"),_T("天漏客")); MySend.MakePostData(_T("homepage"),_T(www.lilu.name)); 4、发送图片。定义好接收数据的指针,以及发送和接收的编码。 TCHAR *pRecvData = NULL; //接收数据的指针 DWORD dwRecvSize = 0; //接收数据的大小 DWORD dwRetSend = 0; //发送函数返回值 int SendCode = HTTP_POST_GB2312,RecvCode =HTTP_POST_GB2312; //发送与接收的编码 dwRetSend = MySend.PostPicDataMethod(_T("c://pic//测试图片.jpg"),_T("filename"), &pRecvData,dwRecvSize, SendCode,RecvCode); //处理接收数据,返回值。 //99:图片不存在 //100:正常成功 //101:服务器无法连接 //102:提交页面无法打开 //103:数据发送失败 //104:服务器处理失败 //500:异常错误 5、处理结果 类自动的根据编译环境,将返回指针转换为LPTSTR类型,所以你只需要定义一个LPTSTR类型的指针,将其地址传递给发送函数即可。类会自己分配内存存储返回的结果,并且会自动释放。所以使用时要注意,当这个类的作用域结束时,相应的接收数据内存也会释放掉,你可以将接收数据另拷贝一份,或者在它的作用域内处理掉也可。 CString strRecv(pRecvData); //将接收数据复制到strRecv中。 6、完毕。 我本地IIS假设服务器,写入上传代码。然后使用软件提交,抓包如下: POST /upload.asp HTTP/1.1 Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/xaml+xml,*/* Accept-Encoding: gzip, deflate Accept-Language: zh-cn Content-Type: multipart/form-data; boundary=-------------2389jhrwfjsjd9823 Cache-Control: no-cache User-Agent: UploadPhoto Host: 192.168.2.111 Content-Length: 39725 ---------------2389jhrwfjsjd9823 Content-Disposition: form-data; name="Crypt" 10 ---------------2389jhrwfjsjd9823 Content-Disposition: form-data; name="type" 200 ---------------2389jhrwfjsjd9823 Content-Disposition: form-data; name="userid" 27EF272F28239E5A34EE223FADFWAFAEaE ---------------2389jhrwfjsjd9823 Content-Disposition: form-data; name="filename"; filename="D:/Lilu.Other/QQ图片/软件工程图解.jpg" Content-Type: image/pjpeg ……………………省略图片二进制数据……………… ---------------2389jhrwfjsjd9823 Content-Disposition: form-data; name="Submit" submit ---------------2389jhrwfjsjd9823-- 这就是整个软件发送的数据,懂http协议的话,很容易理解这些数据。服务器返回: HTTP/1.1 200 OK Server: Microsoft-IIS/5.1 Date: Wed, 04 Nov 2009 02:48:12 GMT Content-Length: 171 Content-Type: text/html Set-Cookie: ASPSESSIONIDSCRSBCRQ=ACBHPAHADINHKHIANAALFKOO; path=/ Cache-control: private <html> <head> <title>文件上传</title> </head> <body> <font size=2>文件上传成功 [ <a href="#" mce_href="#" οnclick=history.go(-1)>继续上传</a> ]</font> </body> </html> 最后贴一下这个类的源代码: ======================================================= 首先是头文件:SendData.h // SendData.h: interface for the CSendData class. // // #if !defined(AFX_SENDDATA_H__F98D6FB7_D797_4947_A17E_13E88D20F35F__INCLUDED_) #define AFX_SENDDATA_H__F98D6FB7_D797_4947_A17E_13E88D20F35F__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include <afxinet.h> #include <string> using std::string; #define HTTP_POST_GB2312 1 //发送和接收的网页编码 #define HTTP_POST_UTF8 2 class CSendData { public: CSendData(); virtual ~CSendData(); void SetServerParam(TCHAR ServerName[100],TCHAR ObjectName[100],WORD Port); //构造协议数据内容 BOOL MakePostData(LPCTSTR pPostName, LPCTSTR pPostValue); BOOL MakePostData(LPCTSTR pPostName,int iPostValue); //发送带图片的数据 DWORD PostPicDataMethod(TCHAR PicPath[MAX_PATH],LPCTSTR pPostName, LPTSTR *pRecvData, DWORD &RecvSize, int SendCode = HTTP_POST_GB2312,//发送和接收的编码 int RecvCode = HTTP_POST_GB2312); //发送文本类数据 DWORD PostDataMethod(LPCTSTR strDataSend, int DataSize, LPTSTR *pRecvData, DWORD &RecvSize, int SendCode = 1,int RecvCode = 1); private: CString m_strBoundary; //数据分隔符 CString m_strHeaderData; //协议头数据 CString m_strPostData; //协议正文数据 CString m_strEndData; //协议尾数据 void MakeHeaderData(); //构造协议头部数据 void MakeEndData(); //构造协议尾部数据 void MakePostPicData(LPCTSTR pPostName, LPCTSTR pPostValue); //构造图片前缀数据 //返回值为图片大小,返回值为0表示不存在。 DWORD GetExistPic(TCHAR PicPath[MAX_PATH]); //服务器参数 INTERNET_PORT m_nPort; TCHAR m_tzObjectName[100]; TCHAR m_tzServerName[100]; /编码转换/ char * m_lpUTF8; //UTF8编码缓存指针 char * m_lpMultiByte; //Multil多字节编码指针 wchar_t * m_wpWideChar; //Widechar编码缓存指针 int m_nUTF8Len; int m_nMultiByteLen; int m_nWideCharLen; void WideCharToUTF8(LPCWSTR wpWideData, int WideLen); void MultiByteToUTF8(LPCSTR lpMultiData, int MultiLen); void UTF8ToWideChar(LPCSTR pUTF8,int UTF8Len); void UTF8ToMultiByte(LPCSTR pUTF8, int UTF8Len); void MultiToWide(LPCSTR strDataSend, int DataSize); void MultiToMulti(LPCSTR strDataSend, int DataSize); void WideToMulti(LPCWSTR wpWideData, int WideLen); }; #endif // !defined(AFX_SENDDATA_H__F98D6FB7_D797_4947_A17E_13E88D20F35F__INCLUDED_) ======================================================== 接着是SendData.cpp文件。 // UploadPhotoDlg.cpp : implementation file // #include "stdafx.h" #include "UploadPhoto.h" #include "UploadPhotoDlg.h" #include "SendData.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif / // CUploadPhotoDlg dialog CUploadPhotoDlg::CUploadPhotoDlg(CWnd* pParent /*=NULL*/) : CDialog(CUploadPhotoDlg::IDD, pParent) { //{{AFX_DATA_INIT(CUploadPhotoDlg) m_strPhotoPath = _T(""); m_nPort = 80; m_strRecvData = _T(""); // m_strObjectName = _T("/frontend_dev.php/device/retriever"); // m_strServerName = _T("trunk.xunhui1.net"); m_strObjectName = _T("/upload.asp"); m_strServerName = _T("192.168.2.111"); m_PostName = _T("userid"); m_PostValue = _T("27EF272F28239E5A34EE223FADFWAFAEaE"); //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CUploadPhotoDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CUploadPhotoDlg) DDX_Text(pDX, IDC_EDIT_OBJECTNAME, m_strObjectName); DDX_Text(pDX, IDC_EDIT_PHOTOPATH, m_strPhotoPath); DDX_Text(pDX, IDC_EDIT_PORT, m_nPort); DDX_Text(pDX, IDC_EDIT_RECVDATA, m_strRecvData); DDX_Text(pDX, IDC_EDIT_SERVERNAME, m_strServerName); DDX_Text(pDX, IDC_EDIT_POSTDATANAME, m_PostName); DDX_Text(pDX, IDC_EDIT_POSTDATAVALUE, m_PostValue); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CUploadPhotoDlg, CDialog) //{{AFX_MSG_MAP(CUploadPhotoDlg) ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BTN_SEND, OnBtnSend) ON_BN_CLICKED(IDC_BTN_FILEOPEN, OnBtnFileopen) //}}AFX_MSG_MAP END_MESSAGE_MAP() / // CUploadPhotoDlg message handlers BOOL CUploadPhotoDlg::OnInitDialog() { CDialog::OnInitDialog(); // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here ((CButton*)GetDlgItem(IDC_RADIO_SENDGB2312))->SetCheck(TRUE); ((CButton*)GetDlgItem(IDC_RADIO_RECVGB2312))->SetCheck(TRUE); return TRUE; // return TRUE unless you set the focus to a control } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CUploadPhotoDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } // The system calls this to obtain the cursor to display while the user drags // the minimized window. HCURSOR CUploadPhotoDlg::OnQueryDragIcon() { return (HCURSOR) m_hIcon; } void CUploadPhotoDlg::OnBtnSend() { // TODO: Add your control notification handler code here GetDlgItem(IDC_BTN_SEND)->EnableWindow(FALSE); UpdateData(TRUE); //定义发送类 CSendData MySend; TCHAR *pRecvData = NULL; //接收数据的指针 DWORD dwRecvSize = 0; //接收数据的大小 DWORD dwRetSend = 0; //发送函数返回值 int SendCode = HTTP_POST_GB2312,RecvCode =HTTP_POST_GB2312; //发送与接收的编码 //设置服务器参数 MySend.SetServerParam((LPTSTR)(LPCTSTR)m_strServerName,(LPTSTR)(LPCTSTR)m_strObjectName,m_nPort); //确定发送方法 if (1 == ((CButton*)GetDlgItem(IDC_RADIO_SENDGB2312))->GetCheck()) { SendCode = HTTP_POST_GB2312; } else { SendCode = HTTP_POST_UTF8; } //确定接收编码 if (1 == ((CButton*)GetDlgItem(IDC_RADIO_RECVGB2312))->GetCheck()) { RecvCode = HTTP_POST_GB2312; } else { RecvCode = HTTP_POST_UTF8; } //必须先构造数据包 MySend.MakePostData(_T("Crypt"),_T("10")); MySend.MakePostData(_T("type"),_T("200")); MySend.MakePostData(m_PostName,m_PostValue); //发送 dwRetSend = MySend.PostPicDataMethod((LPTSTR)(LPCTSTR)m_strPhotoPath,_T("filename"), &pRecvData,dwRecvSize, SendCode,RecvCode); //处理接收数据 //99:图片不存在 //100:正常成功 //101:服务器无法连接 //102:提交页面无法打开 //103:数据发送失败 //104:服务器处理失败 //500:异常错误 if (dwRetSend == 100) { MessageBox(_T("发送成功")); } else if (dwRetSend == 99 ) { MessageBox(_T("发送成功")); } else if (dwRetSend == 101 ) { MessageBox(_T("服务器无法连接")); } else if (dwRetSend == 102 ) { MessageBox(_T("提交页面无法打开")); } else if (dwRetSend == 103 ) { MessageBox(_T("数据发送失败")); } else if (dwRetSend == 104 ) { MessageBox(_T("服务器处理失败")); } else if (dwRetSend == 500 ) { MessageBox(_T("异常错误")); } //更新返回数据框 m_strRecvData = pRecvData; UpdateData(FALSE); GetDlgItem(IDC_BTN_SEND)->EnableWindow(TRUE); } void CUploadPhotoDlg::OnBtnFileopen() { // TODO: Add your control notification handler code here TCHAR tzFilter[] = _T("jpg图片(*.jpg;*.jpeg)|*.jpg;*.jpeg|gif图片(*.gif)|*.gif|所有文件(*.*)|*.*||"); CFileDialog dlg(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_ENABLESIZING|OFN_EXPLORER, tzFilter,NULL); if (dlg.DoModal() == IDOK) { m_strPhotoPath = dlg.GetPathName(); UpdateData(FALSE); } }