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 >

ExpandedBlockStart.gifContractedBlock.giftypedef 
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并且设置连接状态

好了,直接贴代码算了

ContractedBlock.gif ExpandedBlockStart.gif tuobao_tcpclient.c
#include <stdio.h>
#include 
<stdlib.h>
#include 
<arpa/inet.h>
#include 
<netdb.h>

#include 
"tuobao_tcpclient.h"

#define BUFFER_SIZE 1024


int tuobao_tcpclient_create(tuobao_tcpclient *pclient,const char *host, int port){
    
struct hostent *he;

    
if(pclient == NULL) return -1;
    memset(pclient,
0,sizeof(tuobao_tcpclient));

    
if((he = gethostbyname(host))==NULL){
        
return -2;
    }

    pclient
->remote_port = port;
    strcpy(pclient
->remote_ip,inet_ntoa( *((struct in_addr *)he->h_addr) ));

    pclient
->_addr.sin_family = AF_INET;
    pclient
->_addr.sin_port = htons(pclient->remote_port);
    pclient
->_addr.sin_addr = *((struct in_addr *)he->h_addr);

    
if((pclient->socket = socket(AF_INET,SOCK_STREAM,0))==-1){
        
return -3;
    }

    
/*TODO:是否应该释放内存呢?*/

    
return 0;
}

int tuobao_tcpclient_conn(tuobao_tcpclient *pclient){
    
if(pclient->connected)
        
return 1;

    
if(connect(pclient->socket, (struct sockaddr *)&pclient->_addr,sizeof(struct sockaddr))==-1){
        
return -1;
    }

    pclient
->connected = 1;

    
return 0;
}

int tuobao_tcpclient_recv(tuobao_tcpclient *pclient,char **lpbuff,int size){
    
int recvnum=0,tmpres=0;
    
char buff[BUFFER_SIZE];

    
*lpbuff = NULL;

    
while(recvnum < size || size==0){
        tmpres 
= recv(pclient->socket, buff,BUFFER_SIZE,0);
        
if(tmpres <= 0)
            
break;
        recvnum 
+= tmpres;

        
if(*lpbuff == NULL){
            
*lpbuff = (char*)malloc(recvnum);
            
if(*lpbuff == NULL)
                
return -2;
        }
else{
            
*lpbuff = (char*)realloc(*lpbuff,recvnum);
            
if(*lpbuff == NULL)
                
return -2;
        }

        memcpy(
*lpbuff+recvnum-tmpres,buff,tmpres);
    }

    
return recvnum;
}

int tuobao_tcpclient_send(tuobao_tcpclient *pclient,char *buff,int size){
    
int sent=0,tmpres=0;

    
while(sent < size){
        tmpres 
= send(pclient->socket,buff+sent,size-sent,0);
        
if(tmpres == -1){
            
return -1;
        }
        sent 
+= tmpres;
    }
    
return sent;
}

int tuobao_tcpclient_close(tuobao_tcpclient *pclient){
    close(pclient
->socket);
    pclient
->connected = 0;
}

现在来看看http协议的头吧

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

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

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

ContractedBlock.gif ExpandedBlockStart.gif html
<FORM METHOD=POST ACTION="http://192.168.1.103/a.b">
<INPUT TYPE="text" NAME="input1">
<INPUT TYPE="submit">    
 
</FORM>

 

看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了。。

 

转载于:https://www.cnblogs.com/linbc/archive/2009/03/21/1400108.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值