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);

这是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     }

然后下面是一个关于多个字段和多个照片,运用一个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在以前认知的基础上,再次的又重新的知识了一番!! 记录些这些,希望对以后学习的人,能够提供一点点帮助!!!

时间: 2024-11-08 04:09:43

C/C++-----------http协议发送字段,文件,单个和多张图片的相关文章

用IO模拟串口协议发送数据

<pre name="code" class="cpp">//文件usend.h #ifndef _USEND_H_ #define _USEND_H_ //====红外接收相关定义============================= #define PuTx_High (P_uTx = 1) //数据高 #define PuTx_Low (P_uTx = 0) //数据低 #define V_SendDatNum 6//6 //发送数据字节数 /

C++实现RTMP协议发送H.264编码及AAC编码的音视频,摄像头直播

C++实现RTMP协议发送H.264编码及AAC编码的音视频 RTMP(Real Time Messaging Protocol)是专门用来传输音视频数据的流媒体协议,最初由Macromedia 公司创建,后来归Adobe公司所有,是一种私有协议,主要用来联系Flash Player和RtmpServer,如FMS, Red5, crtmpserver等.RTMP协议可用于实现直播.点播应用,通过FMLE(Flash Media Live Encoder)推送音视频数据至RtmpServer,可

(转)C++实现RTMP协议发送H.264编码及AAC编码的音视频,摄像头直播

转:http://www.cnblogs.com/haibindev/archive/2011/12/29/2305712.html C++实现RTMP协议发送H.264编码及AAC编码的音视频 RTMP(Real Time Messaging Protocol)是专门用来传输音视频数据的流媒体协议,最初由Macromedia 公司创建,后来归Adobe公司所有,是一种私有协议,主要用来联系Flash Player和RtmpServer,如FMS, Red5, crtmpserver等.RTMP

TCP协议传输大文件读取时候的问题

TCP协议传输大文件读取时候的问题 大文件传不完的bug 我们在定义的时候定义服务端每次文件读取大小为10240, 客户端每次接受大小为10240 我们想当然的认为客户端每次读取大小就是10240而把客户端的读下来的文件想当然大小每一次都加上10240 而实际上服务端发送文件send每次发送不一定是一次性把10240的文件传送完,可能分了好几次进行发送至缓冲区这我们实际文件大小就不一定是10240 解决办法: 1.对于每次服务端所发送的文件内容及大小都发送给客户端,让客户端一一对应读取 2.实时

Java基础知识强化之网络编程笔记06:TCP之TCP协议发送数据 和 接收数据

1. TCP协议发送数据 和 接收数据 TCP协议接收数据:• 创建接收端的Socket对象• 监听客户端连接.返回一个对应的Socket对象• 获取输入流,读取数据显示在控制台• 释放资源 TCP协议发送数据: • 创建发送端的Socket对象• 这一步如果成功,就说明连接已经建立成功了.• 获取输出流,写数据• 释放资源 2. 代码实现: (1)发送端: 1 package cn.itcast_06; 2 3 import java.io.IOException; 4 import java

Android面向HTTP协议发送get请求

/** * 採用get请求的方式 * * @param username * @param password * @return null表示求得的路径有问题,text返回请求得到的数据 */ public static String getRequest(String username, String password) { try { String path = "http://172.22.64.156:8080/0001AndroidWebService/LoginServlet?use

HLS(HTTP Live Streaming)协议之m3u8文件生成方式

HLS(HTTP Live Streaming)是Apple的动态码率自适应技术.主要用于PC和Apple终端的音视频服务.包括一个m3u(8)的索引文件,TS媒体分片文件和key加密串文件. HLS的关键其实是生成m3u8索引文件和TS媒体分片,下面我将通过以下几个步骤讲述m3u8及TS媒体分片的生成: 第一步---获取TS文件: TS(Transport Stream)既传输流,标准制定于mpeg2文档协议中,当时TS格式主要是为了数字电视传输而制定,制定的年限相当早,在网上能找到很完备的m

使用websocket发送图片文件

Websocket是HTML5中的一个传输数据控件. 眼下在主流的浏览器中都提供了支持. 关于websocket的相关协议能够在网上查到,关于怎样建立连接等操作大家能够查询协议获得.本文主要讨论怎样进行传输数据. 在client使用的是Chrome浏览器,在server端使用PHP开发websocket协议. Websocket协议一个frame的标准格式: 0                   1                   2                   3 0 1 2 3

Java基础知识强化之网络编程笔记03:UDP之UDP协议发送数据 和 接收数据

1. UDP协议发送数据 和 接收数据 UDP协议发送数据: • 创建发送端的Socket对象 • 创建数据,并把数据打包 • 调用Socket对象的发送方法,发送数据包 • 释放资源  UDP协议接收数据:       • 创建接收端的Socket对象      • 创建数据包,接收数据(接收容器)      • 调用Socket对象的接收方法,接收数据包      • 解析数据包,并显示在控制台      • 释放资源 2. 代码实现 (1)首先我们先写发送端的程序,如下: 1 packag