C/C++ http协议发送字段,文件,单个和多张图片
关于c/c++ 网络编程,无论在linux还是windows,要说到自由性,和安全性,socket无疑是比较好的!对于socket,因为它的传输协议只有两种tcp和udp,属于网络层,这里我们不去重点讨论。
关于应用层协议http,如何用C/C++的socket来实现数据传输和下载呢?
1. http是超文本协议,用在html文件中,那么对于html是如何传输数据呢?
通过post或者get传输表单数据,当然http还有其他的方式head,put ,delete,option,trace等方式。head和get差不多,唯一的区别就是head只返回协议头,put和post也很相似,但是可惜html表单数据不支持这一特性,put和post的区别在于,put说出来资源放置于服务器的位置,而post没有,post将这项权利给予服务器来使用。delete顾名思义,就是指定删除在服务器上的资源,option一般用来获取当前URl所支持请求的方法(就是上诉的六种)。
对于c/c++传输单数据,get方法:
get方法, 形如: http://i.cnblogs.com/EditPosts.aspx?opt=1
这个表单传输的数据就是1,其中键值就是opt,这个需要和服务器上的保持一致
对于一个简单的html
1 <html> 2 <head><title>右边</tile></head> 3 <body> 4 <form > 5 <input type="text", name="opt" > 1 </input> 6 </form> 7 </body> 8 </html>
opt就是键值
那么用socket如何实现:
首先,windows下,我们
1. 先要启动异步套接字启动命令
//初始化套结字动态库2 if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) //异步套接字启动命令3 /版本(次,主) //返回socket实现细节信息4 {5 system("WSAStartup failed!\n");6 system("pause");7 return -1;8 }
2.在想linux下一样,创建套接字
sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
3.绑定端口号,和设置要访问的服务器主机地址
//设置服务器地址servAddr.sin_family = AF_INET;servAddr.sin_addr.s_addr = inet_addr("203.195.192.24");servAddr.sin_port = htons((short)80);
4.连接服务器
1 retVal = connect(sHost, (LPSOCKADDR)&servAddr, sizeof(servAddr));
5.然后接收信息字段
char *pHttpGet = "GET %s?%s HTTP/1.1\r\n""Host: %s:%d\r\n\r\n"; char strHttpGet[1024] = { 0 };//ZeroMemory(strHttpGet, BUF_SZIE); //初始化内存char msg[]="username=Gjxun&pwd=sssssss";sprintf(strHttpGet, pHttpGet, addr, msg, host, port);int var = send(sHost, strHttpGet, strlen(strHttpGet), 0);
recv(sHost,rebuf ,sizeof(rebuf),0);
最后关闭的时候。需要用这个来关闭异步套接字
1 WSACleanup( );
这是http的基本流程,对于get发送单个或者多个表单数据如上面所示
对于post而言,情况 会多些,也会复杂些
1.如果发送的是单个或者多个字段信息,那么我们的处理方式大致可以有下面这两种
第一种: 就像get一样,只不过单纯的将数据放置于协议的后面,需要注意点的是,格式比较重要,特别协议头和正文部分之间需要各一个空行:
下面的msg亦可以和get一样写成 msg="username=Gxjun&pwd=ssssss"; 还有content-Length的长度: 是正文和正文数据以及尾部长度之后不需要算协议头长度,不然会,当将连接改为Connection: Keep-Alive 出现服务器长时间接受现象。---指导服务器接受到结尾帧或者数据长度达到那个长度为止,才会响应刚才的动作!!!!
1 void sendPost1(char* addr, char * host, char *msg, int port) {2 char *pHttpPost = "POST %s HTTP/1.1\r\n"3 "Host: %s:%d\r\n"4 "Content-Type: application/x-www-form-urlencoded\r\n"5 "Content-Length: %d\r\n\r\n"6 "%s";7 13 char strHttpPost[1024] = { 0 }; 14 //ZeroMemory(strHttpGet, BUF_SZIE); //初始化内存 15 sprintf(strHttpPost, pHttpPost, addr, host, port, strlen(msg), msg); 16 int var = send(sHost, strHttpPost, strlen(strHttpPost), 0); 17 if (var < 0) { 18 MessageBoxA(NULL, "请求发送失败!", 0, 0); 19 return; 20 } 21 }
另一种方式:多种数据表单的形式:协议头部分,将Content-Type: multipart/form-data; 同时还需要加上一个分割标识,即boundary = Gxjunnndgx ,
整体上就是设置为 Content-Type: multipart/form-data; boundary=71b23e4066ed\r\n";
其他部分参开rfc2038部分。
所以对于单个或者多个字段表单而言:
比如: 需要像如下的html文件一样将username和pwd的键值数据发送给服务器数据数据:
<html><head></head> <body><form action="xxx.xxx.xxxx" method="post"><input type="text" name="username">Gxjun</input><input type="password" name="pwd">ssssss</input> <form> </body> </html>
1 void sendPost(char* addr, char * host,string username,string psw, int port){2 3 std::string header("");6 std::string u_content(""); //用户名7 std::string p_content(""); //密码8 9 //----------------------post头开始-------------------------------- 10 header += "POST "; 11 header += addr; 12 header += " HTTP/1.1\r\n"; 13 header += "Host: "; 14 header += host; 15 header += "\r\n"; 16 header += "Connection: Keep-Alive\r\n"; 17 header += "Accept: */*\r\n"; 18 header += "Pragma: no-cache\r\n"; 19 header += "Content-Type: multipart/form-data; boundary=71gxjun\r\n"; 20 21 //用户名数据表单 22 u_content += "--71gxjun\r\n"; 23 u_content += "Content-Disposition: form-data; name=\"u\"\r\n\r\n"; 24 u_content += username+"\r\n"; 25 26 //密码数据表单 27 p_content += "--71gxjun\r\n"; 28 p_content += "Content-Disposition: form-data; name=\"p\"\r\n\r\n"; 29 p_content += psw+"\r\n"; 30 //post尾时间戳 31 std::string strContent("--71gxjun--\r\n\r\n"); 32 char temp[64] = { 0 }; 33 //注意下面这个参数Content-Length,这个参数值是:http请求头长度+请求尾长度+文件总长度 34 // 就分块传送 35 sprintf(temp, "Content-Length: %d\r\n\r\n", 36 p_content.length()+u_content.length() + strContent.length()); 37 header += temp; 38 std::string str_http_request; 39 str_http_request.append(header); 40 41 //----------------------post头结束----------------------------------- 42 //发送post头 43 send(sHost, str_http_request.c_str(), str_http_request.length(), 0); 44 Sleep(0.2); 45 send(sHost, p_content.c_str(), p_content.length(), 0); 46 Sleep(0.2); 47 send(sHost, u_content.c_str(), u_content.length(), 0); 48 Sleep(0.2); 49 ::send(sHost, strContent.c_str(), strContent.length(), 0); 50 Sleep(0.2); 51 } 52
对于boundary=abcdegxjun 这部分的数据可以随意定义,但不要太简单,不然可能会和数据混淆,上面是两个字段的发送,所以需要两部分的正文加正文数据,对于尾部的结束标识,前面需要“--”两个横短线后面也需要两个横短线“--”,对于中间的分割标志,只需要前面有“--”就可以了! 还需要注意的是数据发送完之后,需要换行,然后再接上分割标识。
4.然后对于文件和照片的传输 ---在linux下,一切接文件,在window下我们也可以将照片看做二进制文件处理
其实文件的传输,都可以作为二进制文件来传输,我们可以将文件
1 char * ReadFile(char *pathpic, int &pic_len){2 //将图片读取出来3 FILE *fp = fopen(pathpic, "rb"); //打开文件4 if (!fp){5 MessageBoxA(NULL, "没有找到文件位置", 0, 0);6 return NULL;7 }8 fseek(fp, 0, SEEK_END); //一直寻找到文件尾部9 pic_len = ftell(fp); //得到图片的长度 10 rewind(fp); //rewind将文件指针指向开头 11 char *pic_buf = new char[pic_len + 1]; //开辟一个空间在堆上 12 memset(pic_buf, 0, pic_len + 1); //清空文件指针 13 //读取文件内容 14 fread(pic_buf,sizeof(char),pic_len,fp); 15 //测试将文件再保存于D:中 16 /* 17 MessageBoxA(NULL, "文件开始", 0, 0); 18 FILE *fpw = fopen("C:\\AA.jpg","wb"); 19 fwrite(pic_buf,sizeof(char), pic_len, fpw); 20 fclose(fpw); //关闭文件流 21 MessageBoxA(NULL, "文件结束", 0, 0); 22 */ 23 fclose(fp); 24 25 return pic_buf; 26 }
对于不同的类型,需要修改不同的Content-Type 比如图片jpg,jpeg等就是需要这种 ,"Content-Type: image/jpeg,对于其他的的类型,不妨去这儿找找,比较详细
http://tool.oschina.net/commons
然后下面是一个关于多个字段和多个照片,运用一个form表单,通过一次post,将数据上传到服务器上! 注: 这里是在c\s模式, 客户端是c++ ,服务器是php
代码如下:
1 char * ReadFile(char *pathpic, int &pic_len){2 //将图片读取出来3 FILE *fp = fopen(pathpic, "rb"); //打开文件4 if (!fp){5 MessageBoxA(NULL, "没有找到文件位置", 0, 0);6 return NULL;7 }8 fseek(fp, 0, SEEK_END); //一直寻找到文件尾部9 pic_len = ftell(fp); //得到图片的长度10 rewind(fp); //rewind将文件指针指向开头11 char *pic_buf = new char[pic_len + 1]; //开辟一个空间在堆上12 memset(pic_buf, 0, pic_len + 1); //清空文件指针13 //读取文件内容14 fread(pic_buf,sizeof(char),pic_len,fp);15 //测试将文件再保存于D:中16 /*17 MessageBoxA(NULL, "文件开始", 0, 0);18 FILE *fpw = fopen("C:\\AA.jpg","wb");19 fwrite(pic_buf,sizeof(char), pic_len, fpw);20 fclose(fpw); //关闭文件流21 MessageBoxA(NULL, "文件结束", 0, 0);22 */23 fclose(fp); 24 25 return pic_buf;26 }27 28 void sendPic(char* addr, char * host, char *pathpic, char* picname, int port, string username, string psw) {29 30 //先读取文件流31 //实名图片读取,等级图片读取32 int Spic_len, Dpic_len;33 char *Spic_data=NULL, *Dpic_data=NULL;34 35 Spic_data=ReadFile(pathpic, Spic_len);36 Dpic_data = ReadFile(picname, Dpic_len);37 std::string header("");38 std::string content(""); //实名文件39 std::string nex_content(""); //等级文件40 std::string u_content(""); //用户名41 std::string p_content(""); //密码42 43 //----------------------post头开始-------------------------------- 44 header += "POST ";45 header += addr;46 header += " HTTP/1.1\r\n";47 header += "Host: ";48 header += host;49 header += "\r\n";50 header += "Connection: Keep-Alive\r\n";51 header += "Accept: */*\r\n";52 header += "Pragma: no-cache\r\n";53 header += "Content-Type: multipart/form-data;boundary=71b23e4066ed\r\n";54 55 //用户名数据表单56 u_content += "--71b23e4066ed\r\n";57 u_content += "Content-Disposition: form-data; name=\"u\"\r\n\r\n";58 u_content += username+"\r\n";59 60 //密码数据表单61 p_content += "--71b23e4066ed\r\n";62 p_content += "Content-Disposition: form-data; name=\"p\"\r\n\r\n";63 p_content += psw+"\r\n";64 65 //发送文件数据66 content += "--71b23e4066ed\r\n";67 content += "Content-Disposition: form-data; name=\"picurl\"; filename=\"";68 content += pathpic;69 content += "\"\r\n";70 content += "Content-Type: image/jpeg \r\n\r\n";71 72 //发送文件数据73 nex_content += "\r\n--71b23e4066ed\r\n";74 nex_content += "Content-Disposition: form-data; name=\"id_account\"; filename=\"";75 nex_content += picname; //picname;76 nex_content += "\"\r\n";77 nex_content += "Content-Type: image/jpeg\r\n\r\n";78 79 //post尾时间戳 80 std::string strContent("\r\n--71b23e4066ed--\r\n");81 char temp[64] = { 0 };82 //注意下面这个参数Content-Length,这个参数值是:http请求头长度+请求尾长度+文件总长度83 // 就分块传送 84 sprintf(temp, "Content-Length: %d\r\n\r\n",85 content.length() + nex_content.length() +p_content.length()+u_content.length() + Spic_len + Dpic_len + strContent.length());86 header += temp;87 std::string str_http_request;88 str_http_request.append(header);89 90 //----------------------post头结束-----------------------------------91 //发送post头 92 send(sHost, str_http_request.c_str(), str_http_request.length(), 0);93 char fBuff[1024];94 int buffsize = 1024; // 每个数据包存放文件的buffer大小 95 int nStart;//记录post初始位置 96 int nSize;//记录剩余文件大小 97 Sleep(0.2);98 //发送用户名表单99 send(sHost, u_content.c_str(), u_content.length(), 0); 100 Sleep(0.2); 101 //发送密码表单 102 send(sHost, p_content.c_str(), p_content.length(), 0); 103 Sleep(0.2); 104 //发送尾部 105 //发送格式 106 send(sHost, content.c_str(), content.length(), 0); 107 Sleep(0.2); 108 send(sHost, Spic_data, Spic_len, 0); 109 Sleep(0.2); 110 //发送等级图片数据 111 send(sHost, nex_content.c_str(), nex_content.length(), 0); 112 Sleep(0.2); 113 send(sHost, Dpic_data, Dpic_len, 0); 114 Sleep(0.2); 115 //如果数据是在够大,需要作调整,可以使用如下的方式,切割文件发送数据 116 /* 117 for (int i = 0; i < Spic_len; i += bufsize) 118 { 119 nStart = i; 120 if (i + bufsize + 1> Spic_len){ 121 nSize = Spic_len - i; 122 } 123 else{ 124 nSize = bufsize; 125 } 126 127 memcpy(fBuff, Spic_data + nStart, nSize); 128 ::send(sHost, fBuff, nSize, 0); 129 Sleep(0.2); //防止毡包 130 } 131 132 //发送等级图片数据 133 ::send(sHost, nex_content.c_str(), nex_content.length(), 0); 134 Sleep(0.2); 135 bufsize = 4096; 136 for (int i = 0; i < Dpic_len; i += bufsize) 137 { 138 nStart = i; 139 if (i + bufsize + 1> Dpic_len){ 140 nSize = Dpic_len - i; 141 } 142 else{ 143 nSize = bufsize; 144 } 145 146 memcpy(fBuff, Dpic_data + nStart, nSize); 147 ::send(sHost, fBuff, nSize, 0); 148 Sleep(0.2); //防止毡包 149 } 150 */ 151 /* 152 for (int i = 0; i < Dpic_len; i += nPacketBufferSize) 153 { 154 nStart = i; 155 if (i + nPacketBufferSize + 1> Dpic_len){ 156 nSize = Dpic_len - i; 157 } 158 else{ 159 nSize = nPacketBufferSize; 160 } 161 162 memcpy(fBuff, Dpic_data + nStart, nSize); 163 ::send(sHost, fBuff, nSize, 0); 164 Sleep(0.2); //防止毡包 165 }*/ 166 167 send(sHost, strContent.c_str(), strContent.length(), 0); 168 Sleep(0.2); 169 170 if (Spic_data == NULL) 171 { 172 MessageBox(NULL, L"文件数据为空", 0, 0); 173 } 174 //释放内存 175 delete Spic_data; 176 delete Dpic_data; 177 178 }
当这些基本做好了之后,就需要看返回的结果:
对于返回http返回结果协议头的简单解析: 如果需要深入研究去看 rfc2616,这里就简单的罗列一些100-500的简单的含义吧
100-199 用于指定客户端应相应的某些动作。 200-299 用于表示请求成功。 300-399 用于已经移动的文件并且常被包含在定位头信息中指定新的地址信息。 400-499 用于指出客户端的错误。 500-599 用于支持服务器错误。
详细的文档,可以看看这个在线文档,http://tool.oschina.net/commons?type=5
学习的过程中参考过几位博主,此处表达谢意,终于对http在以前认知的基础上,再次的又重新的知识了一番!! 记录些这些,希望对以后学习的人,能够提供一点点帮助!!!
C/C++ http协议发送字段,文件,单个和多张图片相关推荐
- ymodem android,【安卓相关】蓝牙基于Ymodem协议发送bin文件,对硬件设备进行升级。...
最近做的一个安卓项目是使用蓝牙基于Ymodem协议传输bin文件,实现对硬件设备进行升级. 做的过程中遇到了不少困难,用我这半吊子的语文水平,记录一下吧 怎么办,平时对各种文件传输协议真的是知之甚少啊 ...
- 野火串口助手协议发送文件通讯协议——XMODEM协议——YMODEM协议
野火串口助手协议发送文件通讯协议 修订历史 日期 版本 更新内容 2020/6/22 0.0.1 首次发布 XMODEM协议 上位机是现实了XModem-CRC16和XModem-1K; XModem ...
- 串口 YModem 协议 发送文件
开发环境: VS2005 .netframework 2.0 语言: C# 运行平台: windows CE 5.0 背景: 这几天在 ...
- http 协议上传文件multipart form-data boundary 说明--转载
原文地址:http://xixinfei.iteye.com/blog/2002017 含义 ENCTYPE="multipart/form-data" 说明: 通过 http ...
- 理光有邮件服务器吗,理光Aficio 3035复印机通过电子邮件发送扫描文件的设定方法及操作步骤...
[转]http://www.hi-office.cn/ricoh/maintenance/4987.html 理光Aficio 3035复印机通过电子邮件发送扫描文件的设定方法及操作步骤 作者:hio ...
- Java开发的B/S程序生成并向客户端发送excel文件:浅谈MIME
Java开发的B/S程序生成并向客户端发送excel文件:浅谈MIME 1.定义 MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型.是设定 ...
- 服务器拒绝发送文件怎么办,服务器拒绝了您发送离线文件
服务器拒绝了您发送离线文件 内容精选 换一换 夜晚或光线暗区域拍摄的图像存在人眼或机器"看不清"暗光区域的情况.针对此类场景,低光照增强可以将图像的暗光区域增强,使得原来人眼不可见 ...
- 上传文件到tftp服务器,网络基础知识:TFTP协议之上传文件
原标题:网络基础知识:TFTP协议之上传文件 上传文件指的是客户端将本地上的文件上传到TFTP服务器上.下面介绍客户端如何进行文件上传,以及上传时所涉及的各类型数据包. 1.工作流程 客户端会向TFT ...
- C++中的Socket编程使用协议发送图片
使用: (1)首先运行服务端,待服务端运行起来: (2)最后运行客户端,输入要传输文件到哪个目标机器的IP地址: (3)输入传输文件的路径及文件(完成的路径),其中包含文件的类型,也就是后缀需要包含( ...
最新文章
- GSA+麦肯锡开年首场线上活动:汽车半导体要变天?
- 烟雾检测电路c语言程序,烟雾报警器电路图大全(六款模拟电路设计原理图详解)...
- 架空输电线路运行规程_[精品课程]金具的种类架空输电线路设计
- qml入门学习(一):hello world
- python rabitmq_3、Python结合RabbitMQ实现消息传递
- ENVI5.3.1使用Landsat 8影像进行预处理及分析实例操作
- linux gcc换成c99标准,关于GCC和C99中可变参数宏
- iOS文本展开收起,使用YYKit展开全文和收起全文,支持图文混排
- iOS开发之定位神器-超简单方式解决iOS后台定时定位
- win 10 读写EFI分区
- GITEE提交代码时出现“文本是相同的,但文件不匹配“问题解决方法
- android10全面屏手势 操作图,丨系统设计丨ZUI 10加入更多全面屏手势
- 海南信用社计算机试题,2021年海南农村信用社计算机笔试内容17
- kaggle竞赛之Hungry Geese比赛
- 在职研究生(多重继承)Python
- dubbo源码导入eclipse
- linux上传网页文件大小,Apache启用GZIP压缩网页传输方法
- 卡特兰数Catalan number的应用
- (更新中)论文中 如何插入 参考文件索引
- Missive是什么软件?协作式电子邮件Missive有什么特点
热门文章
- linux 后端的进程,linux后台启动进程
- java+web+415_使用json返回HTTP状态415的Web服务 - 不支持的媒体类型
- python连不上树莓派_Python实现树莓派WiFi断线自动重连
- 你的元器件为什么会无缘无故地失效了?
- verilog正弦电压PWM波产生
- python共享文件权限_利用Python实现在同一网络中的本地文件共享方法
- python写word模板_Python3操作Office之Word模板技术
- mfc 算方差函数_什么影响了你的工资?方差分析告诉你
- sdk没有登录什么意思_检查肝功能没有空腹,影响效果吗?转氨酶100是什么意思?...
- 笔记本电脑没有鼠标怎么右键_联想笔记本电脑没有声音怎么修复