使用c语言实现的http get post请求

2023-05-16

这里写目录标题

  • 背景
    • 参考案例
  • 具体实现
    • 请求代码模板
    • flask接收示例

背景

我目前需要解决一个需求,将一个c工程中的特定数据转发到VUE前端框架上做界面展示,且该框架已经有后端为flask框架。所以得考虑如何将c工程中的数据发送到python中。容易知道,进程间通信的方式有管道、信号量、消息队列、共享内存、套接字等。为了简易实现上述功能和尽量不影响他们两边原先进程的功能,使用套接字发送封装的数据做http请求给flask后端,这样来实现数据转发。
HTTP(超文本传输协议)是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP请求的资源由统一资源标识符(Uniform Resource Identifiers,URI)来标识。具体区别这篇博客讲的很详细。总而言之http连接=以http协议为通信协议的tcp连接,http协议可以由tcp协议封装报文而来,现在要解决的就是c的套接字如何封装成符合http协议的get/post请求。

参考案例

最开始找了网上很多案例,tcp套接字细节此处不赘述。http请求就是其tcp传输附上对应http请求的报文,但是实际测试不对,没有相应返回。猜想到可能测试环境不同封装格式也要改变,所以使用wireshark抓包软件抓了个具体的数据包来分析。
使用的get、post请求的html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>GET and POST</title>
</head>
<body>
    <form action = "http://localhost:5000" method = "get">
         <table>
            <tr>
                <td>Name</td>
                <td><input type ="text" name ="username"></td>
            </tr>
            <tr>
                <td>Password</td>
                <td><input type ="password" name ="password"></td>
            </tr>
            <tr>
                <td><input type = "get submit"></td>
            </tr>
        </table>
    </form>
    <form action = "http://localhost:5000" method = "post">
        <table>
           <tr>
               <td>Name</td>
               <td><input type ="text" name ="username"></td>
           </tr>
           <tr>
               <td>Password</td>
               <td><input type ="password" name ="password"></td>
           </tr>
           <tr>
               <td><input type = "post submit"></td>
           </tr>
   </table>
     </form>
</body>
</html>

后端flask接收代码

from flask import Flask, request
app = Flask(__name__)

@app.route('/', methods=['GET'])
def index():
    username = request.args.get('username')
    password = request.args.get('password')
    if username == "xugaoxiang" and password == "xugaoxiang":
        return f"<html><body>Welcome {username}</body></html>"
    else:
        return f"<html><body>Welcome!</body></html>"

@app.route('/', methods=['POST'])
def index():
    username = request.form['username']
    password = request.form['password']
    if username == "xugaoxiang" and password == "xugaoxiang":
        return f"<html><body>Welcome {username}</body></html>"
    else:
        return f"<html><body>Welcome!</body></html>"

if __name__ == '__main__':
    app.run(debug=True)

测试案例取自此教程,贴出教程源码链接:https://github.com/xugaoxiang/FlaskTutorial
其抓包结果如下所示:
只需要关注http数据包中的tcp报文内容即可。
在这里插入图片描述

具体实现

注:为了解决大小端和数据位数不统一的问题,我是将所有数据转为字符串来发送。如果想要发送json等数据格式同样用抓包看下具体如何封装即可,此处简易的实现先不考虑那些功能。
有了上面的数据样本,进行下面c代码的封装转发。使用环境不同,部分函数可能有所变化。这里只展示基础模板。
真正通用的是下面这段补齐信令的函数

void addget(const char* str1)                 //补齐get信令数据
{
    strcat(str1, "Host: 127.0.0.1\r\n");//cname记录不影响连接,此处不做修改
    strcat(str1, "Content-Type: text/html\r\n\r\n");
}

void addpost(char* str1, const char* data)    //补齐post信令数据
{
    char postlength[128];

    sprintf(postlength, "%d\r\n", strlen(data + 1));
    strcat(str1, "Host: 127.0.0.1\r\n");//cname记录不影响连接,此处不做修改
    strcat(str1, "Content-Type: application/x-www-form-urlencoded\r\n");
    strcat(str1, "Content-Length: ");
    strcat(str1, postlength);
    strcat(str1, "\r\n\r\n");
    strcat(str1, data + 1);		
}
/* 调用方式
		//data即为传输而来的数据
        case get_test:{	        // 封装成http的get请求 
            strcpy(str1, "GET /getsometing?");
            strcat(str1, data + 1);
            strcat(str1, " HTTP/1.1\r\n");
            addget(str1);
            break;
        }
        case post_test:{	    // 封装成http的post请求 
            strcpy(str1, "POST /postsometing HTTP/1.1\r\n");
            addpost(str1, data);
            break;						
        }
*/

请求代码模板

只讨论http请求方面内容,展示基础的tcp套接字绑定及封装http请求流程

#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <windows.h>
#include <pthread.h>  
#include <assert.h>

#define PORT 5000	// 设定发送端口
#define BUFSIZE 1024
#define DATASIZE 2000

enum send_flask_type {
    start=1, 
    accomplish, 
    get_test,
    post_test
};

// 实现函数,flaskip为http请求的ip地址 此处为环回地址127.0.0.1 data为传输数据(例如type=start) send_type设定传输方式
int HandleFlask(const char* flaskip, const char* data, int send_type)
{
	int i, sockfd_flask;
	fd_set   t_set1;
	struct timeval  timeset;
    struct sockaddr_in flaskaddr;
    char str1[2 * DATASIZE], buf[BUFSIZE];

    //* 创建flask连接套接字 *//
	if ((sockfd_flask = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
		printf("创建网络连接失败,本线程即将终止!\n");
		return -1;
	}
	flaskaddr.sin_family = AF_INET;
	flaskaddr.sin_addr.s_addr = inet_addr(flaskip);
	flaskaddr.sin_port = htons(PORT);
	memset(&flaskaddr.sin_zero, 0, 8);
	if (connect(sockfd_flask, (struct sockaddr *)&flaskaddr, sizeof(flaskaddr)) < 0){
		printf("连接到flask服务器失败!\n");
		return -1;
	}
    // printf("连接Flask服务器成功\n");

    switch(send_type) {
        case get_test:{	        /* 封装成http的get请求 */
            strcpy(str1, "GET /getsometing?");
            // if(SplitStr(data + 1, str1) < 0) { //将data中的tpye数字类型转成字符串并添加至str1
            //     printf("需要转发的报文格式有误\n");
            //     return -1;
            // }
            strcat(str1, data + 1);
            strcat(str1, " HTTP/1.1\r\n");
            addget(str1);
            break;
        }
        case post_test:{	    /* 封装成http的post请求 */ 
            strcpy(str1, "POST /postsometing HTTP/1.1\r\n");
            addpost(str1, data);
            break;						
        }
        default:{
            printf("接收到无效格式,舍弃\n");
            return 0;
        }
    }

    i = send(sockfd_flask, str1, strlen(str1), 0);
    if (i < 0) {
        // printf("发送失败!错误代码是%d,错误信息是'%s'\n",errno, strerror(errno));
        printf("发送数据给flask失败!错误代码是%d\n", WSAGetLastError());//windows获取erron
        closesocket(sockfd_flask);
        return -1;
    }
    else {
        // printf("消息发送至flask成功,共发送了%d个字节!send_type=%d \n", i, send_type);
    }

    // python安装插件eventlet后,外部http访问后flask不会立即关闭套接字
    // (即falsk return后不会发送空的tcp报文),
    // 所以此修改为不考虑复杂场景只接收一次flask的http返回数据后就关闭套接字    
    FD_ZERO(&t_set1);
    FD_SET(sockfd_flask, &t_set1);
    timeset.tv_sec= 0;
    timeset.tv_usec= 100000;                //扫描堵塞时间100ms
    i= select(sockfd_flask +1, &t_set1, NULL, NULL, &timeset);

    if (i == 0) {
        // printf("长时间未接收到flask http响应,跳过\n");
        // continue;
        // break;
    }
    else if (i < 0) {
        printf("在读取flask数据报文时SELECT检测到异常,该异常导致线程终止!\n");
        closesocket(sockfd_flask);
        return -1;
    }
    else {
        memset(buf, 0, sizeof(buf) );
        i = recv(sockfd_flask, buf, sizeof(buf), 0);
        if (i <= 0) {
            closesocket(sockfd_flask);
            if (i  == 0) {  
                // printf("与flask通信的http套接字关闭\n");
                return 0;
            }
            else {
                printf("接收flask数据报出现错误!错误代码是%d\n", WSAGetLastError());    //windows获取erron
                return -1;
            }
        }
        else {  //对http返回值进行处理
            // printf("flask返回值%s\n", buf);
            // continue;
            // break;       
        }
    }
    closesocket(sockfd_flask);
	return 0;
}

flask接收示例

			***flask后端测试用****
@app.route('/getsometing', methods=['GET'])
def gettest():
    type = request.args.get('type')
    src = request.args.get('src')
    dst = request.args.get('dst')
    print(f"get data: type={type},src={src},dst={dst}")
    return f"<html><body>get return: type={type},src={src},dst={dst}</body></html>"

@app.route('/postsometing', methods=['POST'])
def posttest():
    type = request.form['type']
    src = request.form['src']
    dst = request.form['dst']
    print(f"post data: type={type},src={src},dst={dst}")
    return f"<html><body>post return: type={type},src={src},dst={dst}</body></html>"

#如果数据量比较大可以这样写

 @app.route('/getsometing', methods=['GET'])
def gettest():
    get_data=request.args.to_dict()
    type = get_data['type']
    cur_time=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) 

    if type == 'Start' : #自己定义的发送数据的type
		pass
    elif type == 'Accomplish' :
		pass 
    elif type == 'change' :
		pass
    else :
        print ("接收到无效数据,将其丢弃")
        with open("log.txt", "a+") as f:
            f.write('\n# ' + cur_time + ' ---------- get error:\n' + json.dumps(get_data))
        return "<html><body> Flask access invalid data </body></html>"

    return "<html><body> data access </body></html>"


@app.route('/postsometing', methods=['POST'])
def posttest():
    post_data = request.form.to_dict()
    print (post_data)
    type = post_data['type']
    cur_time=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) 

    if type == "change":
		pass
    else :
        print ("接收到无效数据,将其丢弃")
        with open("log.txt", "a+") as f:
            f.write('\n# ' + cur_time + ' ---------- post error:\n' + json.dumps(post_data))
        return "<html><body> Flask access invalid data </body></html>"

    return "<html><body> data access </body></html>"
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用c语言实现的http get post请求 的相关文章

  • Android - 使用 HttpURLConnection 来 POST XML 数据

    我遇到了一些死胡同 需要一些帮助 请 我对 Android 开发 以及一般编码 非常陌生 基本上我需要使用 HttpURLConnection 将 XML 数据发布到 URL 但无法让它工作 我的应用程序从 GET 请求读取并传递 XML
  • 通过 HTTPS 包含 Twitter Widgets.js

    当我们包含以下内容时 我在我们网站上的 HTTPS 服务页面上的混合内容方面遇到了一个小问题http platform twitter com widgets js http platform twitter com widgets js
  • 发布后忽略基本标签

    在 Chrome 上我收到错误Refused to execute a JavaScript script Source code of script found within request 在发布包含域名的数据后 另请注意任一页面上都缺
  • 在弹性搜索中使用 GET/POST 时的不同结果

    我正在通过 Elastic Search Head 插件尝试弹性搜索 当我通过 POST 提交查询时 结果符合预期 但是 当我使用 GET 尝试相同的查询时 我总是会返回索引中的所有值 那么 如何通过 GET 将查询传递到弹性搜索服务器 以
  • iOS 安全性将带有密码的数据发送至服务器或从服务器发送数据

    我正在构建一个应用程序 需要在服务器执行任何操作之前从用户设备发送密码以在服务器上进行身份验证 事情是这样的 用户的手机上有一个纯文本密码 该密码也在服务器中以 bcrypt 二进制文件的形式存在 用户想要从数据库中获取某些内容 因此用户通
  • WCF - 进行多次调用时随机客户端超时

    我有一个WPF客户端通过以下方式请求数据WCF服务托管于IIS 7 服务方法调用存储过程 SQL 2012 using EF检索一些数据 由于需要加载大量数据 因此客户端会多次调用服务方法 以 分解 数据加载并避免大量负载和超时 我们使用生
  • 内容长度标头与分块编码

    我正在尝试权衡设置的利弊Content LengthHTTP 标头与使用分块编码从我的服务器返回 可能 大文件的比较 使用持久连接需要其中之一来符合 HTTP 1 1 规范 我看到了的优点Content Length标头是 下载对话框可以显
  • 如何让 NSURLRequest 获取 Twitter 请求令牌?

    我正在尝试使用以下代码从 Twitter 获取请求令牌 NSMutableURLRequest mURLRequest NSMutableURLRequest alloc initWithURL NSURL URLWithString ht
  • 从开放的 HTTP 流中读取数据

    我正在尝试使用 NET WebRequest WebResponse 类来访问 Twitter 流 API 此处 http stream twitter com spritzer json 我需要能够打开连接并从打开的连接中增量读取数据 目
  • 有人成功用 Robolectric 模拟 HttpRequests 吗?

    我刚刚开始使用 Robolectric 模拟大多数 Android 类似乎工作正常 但是当我的测试类尝试创建 DefaultHttpClient 时 它会收到可怕的 Stub 错误 被测试的类在这一行失败 HttpClient httpcl
  • PHP 是否有与 Java 的 RequestDispatcher.forward 等效的功能?

    在 Java 中我可以编写一个非常基本的 JSPindex jsp像这样 这样做的效果是用户请求index jsp 或者只是包含目录 假设index jsp是目录的默认文档 将会看到home action没有浏览器重定向 即 forward
  • PHP:如何获取
    中的名称值

    有没有办法获取form标签中name属性的值 我正在使用 PHP 但在 中没有看到它 POST 有没有办法获取form标签中name属性的值 我正在使用 PHP 但在 POST 中没有看到它 不 表单的名称属性永远不会设置为作为 POST
  • Vertx HttpClient getNow 不工作

    我的 vertx HttpClient 有问题 下面的代码显示使用 vertx 和纯 java 测试 GET Vertx vertx Vertx vertx HttpClientOptions options new HttpClientO
  • 使用 PHP 将表单数据发送/发布到 URL [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我有一个通过 POST 提交的表单 提交表单后我捕获变量 如何连接表单数据 然后将其 POST 到 url 然后重新定向到感谢页面 这不是确
  • asp.net core http 如果没有内容类型标头,则删除 `FromBody` 忽略

    我在 http 中使用 bodyDELETE要求 我知道目前删除主体是非标准的 但是允许的 使用时出现问题HttpClient它不允许删除请求的正文 我知道我可以使用SendAsync 但我宁愿让我的 API 更加灵活 我希望这个机构是可选
  • 按照约定应返回哪些 REST PUT/POST/DELETE 调用?

    根据 REST 意识形态 PUT POST DELETE 请求的响应正文中应该包含什么 返回码呢 是HTTP OK enough 如果有的话 这种约定的原因是什么 我发现了一篇描述 POST PUT 差异的好文章 发布与放置 http ww
  • 如何解析 Content-Disposition 标头以检索文件名属性?

    使用 go 如何解析从 http HEAD 请求检索到的 Content Disposition 标头以获取文件的文件名 此外 如何从 http HEAD 响应中检索标头本身 这样的事情正确吗 resp err http Head http
  • 如何使用 Emacs 通过 HTTP 打开远程文件?

    大多数开源软件都通过某些 HTTP 服务公开其代码 我想从 Emacs 打开并浏览此类代码 但 AFAICS trapmp 只允许ssh and ftp 因此 我的第一个问题是如何打开 HTTP URL 以便在 Emacs 中进行读取 然后
  • 使用特定 HTTP 方法链接到页面 (DELETE)

    如何像 Rails 那样链接到页面并让浏览器使用 DELETE 方法调用它 我试过 a href DELETE ME a 但不起作用 我使用 Node js 所以我可以用它来处理 DELETE 方法 你不能 链接只会触发 GET 请求 您可
  • iOS 上的多个 HTTP 请求与单个 TCP 连接

    我正在开发一个 iPhone 应用程序 它使用我控制的基于 Web 的 API 连接到持续打开的 TCP 端口并通过 TCP API 发出请求 或者为我想要获取的所有数据发出新的 HTTP 请求 会更快或更高效吗 我认为差异可以忽略不计 但

随机推荐

  • VIM3刷系统

    一 升级到最新系统 如果你的板子上已经运行的是官方发布的Ubuntu固件 xff0c 那么你可以通过如下命令升级系统到最新版本 span class token function sudo span span class token fun
  • 设置Chrome页面为黑色

    文章目录 1 设置主题2 设置页面 1 设置主题 设置 gt 外观 gt 主题背景 gt 选择一个黑色的主题 2 设置页面 输入chrome flags enable force dark将其设置为Enable即可
  • 网线每根的含义以及类别和距离传输问题

    文章目录 1 八芯线每根的含义2 传输距离限制3 双绞线的主要分类 1 八芯线每根的含义 网线采用8根线芯 xff0c 主要是为了减少电磁信号的相互干扰 xff0c 只用四根 xff0c 另外四根可做备份使用 每两根按一定的密度缠绞在一起
  • Windows快捷键

    文章目录 1 创建虚拟桌面2 虚拟桌面间切换3 虚拟桌面关闭4 锁住PC5 显示桌面6 从任务栏打开新应用7 两个应用分屏8 应用切换9 打开文件管理视窗10 打开放大镜11 截取屏幕12 打开操作中心13 进入设置14 与Cortana或
  • ubuntu(18):对‘pthread_create’未定义的引用

    报错 xff1a 对 pthread create 未定义的引用 usr local lib libbenchmark a benchmark runner cc o xff1a 在函数 benchmark internal Benchma
  • Git修改与删除commit记录

    Git修改与删除commit记录 修改commit信息删除未push的commit删除已push的commit 修改commit信息 1 修改最近一次commit的信息 git commit span class token operato
  • 电机转矩、功率、转速之间的关系及计算公式

    P 61 W T 61 FS T 61 FV T 61 F R V 61 2 RN N 转速 所以 P 61 FV 61 T R 2 RN 61 2 TN T 61 P 2 n 用千瓦 xff08 KW xff09 和转 分 xff08 r
  • 使用示波器测量串口波特率

    使用示波器测量串口波特率 波特率和bit时间计算关系基础概念基础知识 xff1a 测量结果 波特率和bit时间计算关系 基础概念 简而言之 xff0c 串口传输的波特率即为每秒钟传输二进制的位数 脱离枯燥乏味的文字描述 xff0c 我们用波
  • 雷达基本原理和组成

    雷达由天线辐射电磁波 xff0c 并通过天线接收目标反射回的电磁波 目标回波 xff0c 然后通过接收机和信号处理机从目标回波中提取信息 提取的目标信息主要包括距离 方位 俯仰和速度等 雷达系统的主要组成如图所示 xff0c 主要由发射机
  • 雷达坐标转换

    function r azimuth elevation flag AE r a etrue flag AE Truenum coordinate conversion XYZ t Angle Az Angle El 1 a 雷达直角坐标系
  • STM32F4驱动GPS(寄存器版)

    本次使用STM32F4的USART1对GPS模块进行驱动 xff0c 并且将GPS的时间 经纬度通过串口打印出来 gps模块与接线图 注意 xff1a GPS 模块需放到窗户边 阳台 xff0c 否则可能收不到 GPS 信号 1 GPS驱动
  • 宏的使用 extern

    https www cnblogs com chulin p 9389254 html
  • 【linux tcp抓包之三次握手】

    linux tcp抓包之三次握手 写在前面三次握手tcpdump参数说明返回值说明IP 127 0 0 1 42004 gt 127 0 0 1 5051Flags S win 43690 options mss 65495 sackOK
  • 姿态解算原理(一)——旋转矩阵

    像我们常见的MPU6050 MPU9250等等都是一种捷联式的惯性元件 xff0c 还是一种低成本的 xff0c 还有一种是平台式的惯性导航 xff0c 不过我们能够用得起的就是低成本的MEMS惯性元件 xff0c 本文的内容是姿态解算的原
  • 【c++编译】makefile与CMake【转】

    makefile与CMake 简单介绍CMake简介检查是否安装CMake常用指令简单应用 简单介绍 我们一般使用makefile文件组织大型C C 43 43 或者含有多个C C 43 43 文件的项目 xff0c 有人认为makefil
  • octomap(1):octomap_server报错MessageFilter [target=odom_combined ]: Dropped 100.00% of messages so far

    报错 xff1a WARN 1652516663 964101392 MessageFilter target 61 odom combined Dropped 100 00 of messages so far Please turn t
  • QT定位地图制作

    一 qt绘画图形 1 创建绘图事件函数 nbsp nbsp nbsp nbsp lt 1 gt paintEvent QPaintEvent QPainter painter this 2 设置画布尺寸 确定原点 X Y轴方向 nbsp n
  • CMake学习

    1 引言 使用cmake管理SLAM工程很方便 xff0c 编译便捷 2 具体学习 推荐 cmake实践 1 MESSAGE在make时的输出 CMakeLists txt内容 PROJECT span class token punctu
  • 【深蓝学院】手写VIO第2章--IMU传感器--笔记

    0 内容 1 旋转运动学 角速度的推导 xff1a 左 61 omega wedge xff0c 而
  • 使用c语言实现的http get post请求

    这里写目录标题 背景参考案例 具体实现请求代码模板flask接收示例 背景 我目前需要解决一个需求 xff0c 将一个c工程中的特定数据转发到VUE前端框架上做界面展示 xff0c 且该框架已经有后端为flask框架 所以得考虑如何将c工程