MFC开发IM---MFC实现http协议传输图片和文本

xiaoxiao2021-02-28  51

要将自己的文件通过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 CHotpimUploadDlg::MakePreFileData(CString &strBoundary, CString &strFileName, int iRecordID) {     CString strFormat;     CString strData; /* 前面的是需要给服务器的一些参数信息, 包括自定义的时间,参数值,比如我们需要identitynumber,time等,name要与服务器一致 */ 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 CHotpimUploadDlg::MakePostFileData(CString &strBoundary) {     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.数据发送过程如下:

[cpp]  view plain  copy    BOOL CHotpimUploadDlg::SendTrack()//发送数据 {      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.发送图片时,截取的数据如下(文本显示):

转载请注明原文地址: https://www.6miu.com/read-2613315.html

最新回复(0)