• linux下纯C简单的HTTP POST请求 客户端模型


    交代一下故事背景,国内某保险公司,最近上ILOG规则引擎项目,题外话,

    对于保险里面的车险核保,真的是相当合适.据说,目前规则引擎最成功的就是ILOG了,我稍微看了一下他们的规则描述语言,感觉好傻啊,用中文描述,我觉得这东西要是可以用导图的那种方式,很发散的方式去处理一定很完美!

    回到正题上,因为公司的核心业务系统是使用pro*c编写的服务运行于IBM AIX上面,并且通过中间件与前端通讯,怎么与java的ILOG规则引擎通讯呢?刚开始想着通过gSoap来实现c对web service的调用,但最后因为安装这个包肯定得通过系统管理员,相当麻烦,而且从来没有用过,不知道是否好用,所以ILOG那边增加一个DTO转换层,即将我们发送过去的xml转换成web services调用,并将返回结果也转换成XML;简单的说就是核心后台通过HTTP POST打包xml发送请求,并且规则引擎那边也返回xml来实现!

    晕,走题有点严重!

    其实无非要实现有两点,

    • TCP客户端的模型
    • HTTP POST协议

    先来看看我的TCP模型的实现


    #ifndef _TUOBAO_TCP_CLIENT_ 
    #define _TUOBAO_TCP_CLIENT_

    #include 
    <netinet/in.h>  
    #include 
    <sys/socket.h>

    typedef 
    struct _tuobao_tcpclient
        
    int socket;
        
    int remote_port;     
        
    char remote_ip[16];  
        
    struct sockaddr_in _addr; 
        
    int connected;       
    }
     tuobao_tcpclient;

    int tuobao_tcpclient_create(tuobao_tcpclient *,const char *host, int port);
    int tuobao_tcpclient_conn(tuobao_tcpclient *);
    int tuobao_tcpclient_recv(tuobao_tcpclient *,char **lpbuff,int size);
    int tuobao_tcpclient_send(tuobao_tcpclient *,char *buff,int size);
    int tuobao_tcpclient_close(tuobao_tcpclient *);

    #endif

    上面的代码应该也不用说太多,光看这个这些函数的命名也差不多知道嘛意思了

    定义一个结构体,有远程IP及端口,连接状态(注:连接状态是为了保持长连接用的,但事实上post请求的时候,根本就没有保持,所以,基本上没用)

    然后是五个tcp函数

     tuobao_tcpclient_create:根据服务器IP或者域名,以及端口填充tcpclient结构,主要是申请个socket及填一下sockaddr_in

    tuobao_tcpclient_conn:连接到远程端口,并修改tcpclient的连接状态

    tuobao_tcpclient_recv:接收远程指定字节数的数据,并分配空间到lpBuf,如果size为0,就阻塞直到连接关闭

    tuobao_tcpclient_send:发送buf,size为buf长度

    tuobao_tcpclient_close:关闭socket并且设置连接状态

    好了,直接贴代码算了

    tuobao_tcpclient.c

    现在来看看http协议的头吧

    虽然搞好几年的asp.net,但是因为微软为我们封装得太好了,一直没有关注http协议的post头应该是怎么样?

    想想,其实很简单,看看人家IE是怎么发出去的就知道了

    ubuntu下,先用nc工作监听一下,win下面随便发个请求

    html

    看nc的响应

    linbc@cheng-ubuntu:~/workspace/httpclient$ sudo nc --80
    [sudo] password 
    for linbc: 
    POST 
    /a.b HTTP/1.1
    Accept: image
    /gif, image/jpeg, image/pjpeg, application/x-ms-application, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-ms-xbap, application/x-shockwave-flash, application/vnd.ms-excel, application/msword, application/vnd.ms-powerpoint, */*
    Accept
    -Language: zh-cn
    Content
    -Type: application/x-www-form-urlencoded
    Accept
    -Encoding: gzip, deflate
    User
    -Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30618)
    Host: 
    192.168.1.103
    Content
    -Length: 12
    Connection: Keep
    -Alive
    Cache
    -Control: no-cache

    input1
    =hello

     好了,基本上知道post请求的http头

     下面直接看代码

    #include "tuobao_tcpclient.h"

    int http_post(tuobao_tcpclient *pclient,char *page,char *request,char **response){

        
    char post[300],host[100],content_len[100];
        
    char *lpbuf,*ptmp;
        
    int len=0;

        lpbuf 
    = NULL;
        
    const char *header2="User-Agent: Tuobao Http 0.1\r\nCache-Control: no-cache\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept: */*\r\n";

        sprintf(post,
    "POST %s HTTP/1.0\r\n",page);
        sprintf(host,
    "HOST: %s:%d\r\n",pclient->remote_ip,pclient->remote_port);
        sprintf(content_len,
    "Content-Length: %d\r\n\r\n",strlen(request));

        len 
    = strlen(post)+strlen(host)+strlen(header2)+strlen(content_len)+strlen(request)+1;
        lpbuf 
    = (char*)malloc(len);
        
    if(lpbuf==NULL){
            
    return -1;
        }

        strcpy(lpbuf,post);
        strcat(lpbuf,host);
        strcat(lpbuf,header2);
        strcat(lpbuf,content_len);
        strcat(lpbuf,request);

        
    if(!pclient->connected){
            tuobao_tcpclient_conn(pclient);
        }

        
    if(tuobao_tcpclient_send(pclient,lpbuf,len)<0){
            
    return -1;
        }
    printf(
    "发送请求:\n%s\n",lpbuf);

        
    /*释放内存*/
        
    if(lpbuf != NULL) free(lpbuf);
        lpbuf 
    = NULL;

        
    /*it's time to recv from server*/
        
    if(tuobao_tcpclient_recv(pclient,&lpbuf,0<= 0){
            
    if(lpbuf) free(lpbuf);
            
    return -2;
        }
    printf(
    "接收响应:\n%s\n",lpbuf);

        
    /*响应代码,|HTTP/1.0 200 OK|
         *从第10个字符开始,第3位
         * 
    */
        memset(post,
    0,sizeof(post));
        strncpy(post,lpbuf
    +9,3);
        
    if(atoi(post)!=200){
            
    if(lpbuf) free(lpbuf);
            
    return atoi(post);
        }


        ptmp 
    = (char*)strstr(lpbuf,"\r\n\r\n");
        
    if(ptmp == NULL){
            free(lpbuf);
            
    return -3;
        }
        ptmp 
    += 4;/*跳过\r\n*/

        len 
    = strlen(ptmp)+1;
        
    *response=(char*)malloc(len);
        
    if(*response == NULL){
            
    if(lpbuf) free(lpbuf);
            
    return -1;
        }
        memset(
    *response,0,len);
        memcpy(
    *response,ptmp,len-1);

        
    /*从头域找到内容长度,如果没有找到则不处理*/
        ptmp 
    = (char*)strstr(lpbuf,"Content-Length:");
        
    if(ptmp != NULL){
            
    char *ptmp2;
            ptmp 
    += 15;
            ptmp2 
    = (char*)strstr(ptmp,"\r\n");
            
    if(ptmp2 != NULL){
                memset(post,
    0,sizeof(post));
                strncpy(post,ptmp,ptmp2
    -ptmp);
                
    if(atoi(post)<len)
                    (
    *response)[atoi(post)] = '\0';
            }
        }

        
    if(lpbuf) free(lpbuf);

        
    return 0;
    }

    int main(){

        tuobao_tcpclient client;

        
    char *response = NULL;
        printf(
    "开始组包\n");
        tuobao_tcpclient_create(
    &client,"127.0.0.1",80);

        
    if(http_post(&client,"/i.php","f1=hello",&response)){
            printf(
    "失败!\n");
            exit(
    2);
        }
        printf(
    "响应:\n%d:%s\n",strlen(response),response);

        free(response);
        
    return 0;
    }

     写个简单的makefile

    objects = tuobao_tcpclient.o httppost.o
    httppost: 
    $(objects)
        cc 
    -o httppost $(objects)
    tuobao_tcpclient.o: tuobao_tcpclient.h
    httppost.o:
    .PHONY : clean
    clean :
        
    @echo 正在移除
        
    -rm httppost $(objects)

     好了,万事OK了。。

  • 相关阅读:
    linux-磁盘挂载脚本
    VSCode插件
    数据模拟--Mock.js
    Vue学习笔记之组件
    Vue学习笔记之动画
    Echarts柱状图常用配置项
    Vue学习笔记之总体结构
    JSON数据格式开发规范
    苹果电脑和手机浏览器的区分
    二维码生成插件(jquery.qrcode.js)说明文档
  • 原文地址:https://www.cnblogs.com/linbc/p/1400108.html
Copyright © 2020-2023  润新知