做一个HTTP POST和消费的响应简单的C例子 [英] Simple C example of doing an HTTP POST and consuming the response

查看:644
本文介绍了做一个HTTP POST和消费的响应简单的C例子的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个非常简单的C程序,做一个HTTP POST。这将需要几个参数,并使用这些构造一个URL。我只想做一个简单的HTTP POST和GET而不使用卷曲的响应(库也不会被这需要运行的机器上安装)。

I would like to create a very simple C application that does an HTTP post. It will take a few parameters, and use these to construct a URL. I'd just like to do a simple HTTP POST and get the response without the use of curl (the libraries are not and will not be installed on the machine this needs to run).

伪code:


  1. 2处理ARGS

  1. Process 2 args

将ARGS为模板网址:<一href=\"http://api.somesite.com/apikey=ARG1&command=ARG2\">http://api.somesite.com/apikey=ARG1&command=ARG2

Put args into template URL: http://api.somesite.com/apikey=ARG1&command=ARG2

确实张贴上生成网址

消费响应

我的谷歌和SO搜索还没有在这个问题上产生了什么。

My Google and SO searches haven't yielded anything on this matter.

推荐答案

对不起,我花了这么长时间才做到这一点 - 我离开的周末

Sorry it took me so long to do this - I was away for the weekend.

一个消息有一个头部分和一个空行分开的消息体。总是需要的空行,即使是没有消息体。头一个命令启动,并有一个冒号和空格分隔键值对其他行。如果有消息体,它可以是你希望它是什么。

A message has a header part and a message body separated by a blank line. The blank line is ALWAYS needed even if there is no message body. The header starts with a command and has additional lines of key value pairs separated by a colon and a space. If there is a message body, it can be anything you want it to be.

在标题和标题必须以carraige回报月底结束的空行和换行对线(见的 HTTP头换行符风格),所以这就是为什么这些线路有\\ r \\ n结尾。

Lines in the header and the blank line at the end of the header must end with a carraige return and linefeed pair (see HTTP header line break style) so that's why those lines have \r\n at the end.

一个URL具有 HTTP的形式://主机:交/路径QUERY_STRING

有提交到网站的要求主要有两种方式:

There are two main ways of submitting a request to a website:


  • GET:查询字符串是可选的,但如果指定,必须是相当短的。正因为这样的标题可能只是GET命令而已。样本消息可能是:

  • GET: The query string is optional but, if specified, must be reasonably short. Because of this the header could just be the GET command and nothing else. A sample message could be:

GET /path?query_string HTTP/1.0\r\n
\r\n


  • POST:什么通常会在查询字符串是在邮件的正文吧。正因为这样的标题需要包括的Content-Type:和内容长度:属性以及POST命令。样本消息可能是:

  • POST: What would normally be in the query string is in the body of the message instead. Because of this the header needs to include the Content-Type: and Content-Length: attributes as well as the POST command. A sample message could be:

    POST /path HTTP/1.0\r\n
    Content-Type: text/plain\r\n
    Content-Length: 12\r\n
    \r\n
    query_string
    


  • 因此​​,要回答你的问题:如果URL您有兴趣张贴到IS <一个href=\"http://api.somesite.com/apikey=ARG1&command=ARG2\">http://api.somesite.com/apikey=ARG1&command=ARG2那么有没有身体或查询字符串,因此,没有理由职位,因为没有什么可放置在邮件的正文中,因此没有什么摆在的Content-Type:和Content-Length的:

    So, to answer your question: if the URL you are interested in POSTing to is http://api.somesite.com/apikey=ARG1&command=ARG2 then there is no body or query string and, consequently, no reason to POST because there is nothing to put in the body of the message and so nothing to put in the Content-Type: and Content-Length:

    我想你可以发布,如果你真的想。在这种情况下,您的信息将如下所示:

    I guess you could POST if you really wanted to. In that case your message would look like:

    POST /apikey=ARG1&command=ARG2 HTTP/1.0\r\n
    \r\n
    

    因此​​,要发送消息的C程​​序需要:

    So to send the message the C program needs to:


    • 创建一个套接字

    • 查找IP地址

    • 打开插座

    • 发送请求

    • 等待响应

    • 关闭套接字

    发送和接收呼叫不一定会全部发送/接收你给他们的数据。它是由你来叫他们在一个循环和发送/接收消息的剩余部分。

    The send and receive calls won't necessarily send/receive ALL the data you give them - they will return the number of bytes actually sent/received. It is up to you to call them in a loop and send/receive the remainder of the message.

    我没有在此示例中做的是任何一种真正的错误检查 - 当它失败我只是退出程序。让我知道,如果你的作品:

    What I did not do in this sample is any sort of real error checking - when something fails I just exit the program. Let me know if it works for you:

    #include <stdio.h> /* printf, sprintf */
    #include <stdlib.h> /* exit */
    #include <unistd.h> /* read, write, close */
    #include <string.h> /* memcpy, memset */
    #include <sys/socket.h> /* socket, connect */
    #include <netinet/in.h> /* struct sockaddr_in, struct sockaddr */
    #include <netdb.h> /* struct hostent, gethostbyname */
    
    void error(const char *msg) { perror(msg); exit(0); }
    
    int main(int argc,char *argv[])
    {
        /* first what are we going to send and where are we going to send it? */
        int portno =        80;
        char *host =        "api.somesite.com";
        char *message_fmt = "POST /apikey=%s&command=%s HTTP/1.0\r\n\r\n";
    
        struct hostent *server;
        struct sockaddr_in serv_addr;
        int sockfd, bytes, sent, received, total;
        char message[1024],response[4096];
    
        if (argc < 3) { puts("Parameters: <apikey> <command>"); exit(0); }
    
        /* fill in the parameters */
        sprintf(message,message_fmt,argv[1],argv[2]);
        printf("Request:\n%s\n",message);
    
        /* create the socket */
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd < 0) error("ERROR opening socket");
    
        /* lookup the ip address */
        server = gethostbyname(host);
        if (server == NULL) error("ERROR, no such host");
    
        /* fill in the structure */
        memset(&serv_addr,0,sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(portno);
        memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);
    
        /* connect the socket */
        if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
            error("ERROR connecting");
    
        /* send the request */
        total = strlen(message);
        sent = 0;
        do {
            bytes = write(sockfd,message+sent,total-sent);
            if (bytes < 0)
                error("ERROR writing message to socket");
            if (bytes == 0)
                break;
            sent+=bytes;
        } while (sent < total);
    
        /* receive the response */
        memset(response,0,sizeof(response));
        total = sizeof(response)-1;
        received = 0;
        do {
            bytes = read(sockfd,response+received,total-received);
            if (bytes < 0)
                error("ERROR reading response from socket");
            if (bytes == 0)
                break;
            received+=bytes;
        } while (received < total);
    
        if (received == total)
            error("ERROR storing complete response from socket");
    
        /* close the socket */
        close(sockfd);
    
        /* process response */
        printf("Response:\n%s\n",response);
    
        return 0;
    }
    

    像其他的答案中指出,4096字节是不是一个非常大的反响。我拿起这个数字随机假设您请求的响应会很短。如果它可以是大,你有两个选择:

    Like the other answer pointed out, 4096 bytes is not a very big response. I picked that number at random assuming that the response to your request would be short. If it can be big you have two choices:


    • 阅读内容长度:从响应标题,然后动态分配足够的内存来容纳整个响应

    • 写入文件的响应,而片到达

    附加信息来回答在评论中提出的问题:

    Additional information to answer the question asked in the comments:

    如果您想在邮件的正文POST数据是什么?然后,你需要包括的Content-Type:和内容长度:头。内容长度:是一切的用于分隔体头中的空行后的实际长度

    What if you want to POST data in the body of the message? Then you do need to include the Content-Type: and Content-Length: headers. The Content-Length: is the actual length of everything after the blank line that separates the header from the body.

    下面是采用下列命令行参数的例子:

    Here is a sample that takes the following command line arguments:


    • 主机

    • 端口

    • 命令(​​GET或POST)

    • 路径(不包括查询数据)

    • 查询数据(放入查询字符串GET和成体POST)

    • 标题的列表(内容长度:是自动的,如果使用POST)

    因此​​,对于原来的问题你可以运行:

    So, for the original question you would run:

    a.out api.somesite.com 80 GET "/apikey=ARG1&command=ARG2"
    

    而对于在评论中问这个问题,你可以运行:

    And for the question asked in the comments you would run:

    a.out api.somesite.com 80 POST / "name=ARG1&value=ARG2" "Content-Type: application/x-www-form-urlencoded"
    

    下面是code:

    #include <stdio.h> /* printf, sprintf */
    #include <stdlib.h> /* exit, atoi, malloc, free */
    #include <unistd.h> /* read, write, close */
    #include <string.h> /* memcpy, memset */
    #include <sys/socket.h> /* socket, connect */
    #include <netinet/in.h> /* struct sockaddr_in, struct sockaddr */
    #include <netdb.h> /* struct hostent, gethostbyname */
    
    void error(const char *msg) { perror(msg); exit(0); }
    
    int main(int argc,char *argv[])
    {
        int i;
    
        /* first where are we going to send it? */
        int portno = atoi(argv[2])>0?atoi(argv[2]):80;
        char *host = strlen(argv[1])>0?argv[1]:"localhost";
    
        struct hostent *server;
        struct sockaddr_in serv_addr;
        int sockfd, bytes, sent, received, total, message_size;
        char *message, response[4096];
    
        if (argc < 5) { puts("Parameters: <host> <port> <method> <path> [<data> [<headers>]]"); exit(0); }
    
        /* How big is the message? */
        message_size=0;
        if(!strcmp(argv[3],"GET"))
        {
            message_size+=strlen("%s %s%s%s HTTP/1.0\r\n");        /* method         */
            message_size+=strlen(argv[3]);                         /* path           */
            message_size+=strlen(argv[4]);                         /* headers        */
            if(argc>5)
                message_size+=strlen(argv[5]);                     /* query string   */
            for(i=6;i<argc;i++)                                    /* headers        */
                message_size+=strlen(argv[i])+strlen("\r\n");
            message_size+=strlen("\r\n");                          /* blank line     */
        }
        else
        {
            message_size+=strlen("%s %s HTTP/1.0\r\n");
            message_size+=strlen(argv[3]);                         /* method         */
            message_size+=strlen(argv[4]);                         /* path           */
            for(i=6;i<argc;i++)                                    /* headers        */
                message_size+=strlen(argv[i])+strlen("\r\n");
            if(argc>5)
                message_size+=strlen("Content-Length: %d\r\n")+10; /* content length */
            message_size+=strlen("\r\n");                          /* blank line     */
            if(argc>5)
                message_size+=strlen(argv[5]);                     /* body           */
        }
    
        /* allocate space for the message */
        message=malloc(message_size);
    
        /* fill in the parameters */
        if(!strcmp(argv[3],"GET"))
        {
            if(argc>5)
                sprintf(message,"%s %s%s%s HTTP/1.0\r\n",
                    strlen(argv[3])>0?argv[3]:"GET",               /* method         */
                    strlen(argv[4])>0?argv[4]:"/",                 /* path           */
                    strlen(argv[5])>0?"?":"",                      /* ?              */
                    strlen(argv[5])>0?argv[5]:"");                 /* query string   */
            else
                sprintf(message,"%s %s HTTP/1.0\r\n",
                    strlen(argv[3])>0?argv[3]:"GET",               /* method         */
                    strlen(argv[4])>0?argv[4]:"/");                /* path           */
            for(i=6;i<argc;i++)                                    /* headers        */
                {strcat(message,argv[i]);strcat(message,"\r\n");}
            strcat(message,"\r\n");                                /* blank line     */
        }
        else
        {
            sprintf(message,"%s %s HTTP/1.0\r\n",
                strlen(argv[3])>0?argv[3]:"POST",                  /* method         */
                strlen(argv[4])>0?argv[4]:"/");                    /* path           */
            for(i=6;i<argc;i++)                                    /* headers        */
                {strcat(message,argv[i]);strcat(message,"\r\n");}
            if(argc>5)
                sprintf(message+strlen(message),"Content-Length: %d\r\n",strlen(argv[5]));
            strcat(message,"\r\n");                                /* blank line     */
            if(argc>5)
                strcat(message,argv[5]);                           /* body           */
        }
    
        /* What are we going to send? */
        printf("Request:\n%s\n",message);
    
        /* create the socket */
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd < 0) error("ERROR opening socket");
    
        /* lookup the ip address */
        server = gethostbyname(host);
        if (server == NULL) error("ERROR, no such host");
    
        /* fill in the structure */
        memset(&serv_addr,0,sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(portno);
        memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);
    
        /* connect the socket */
        if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
            error("ERROR connecting");
    
        /* send the request */
        total = strlen(message);
        sent = 0;
        do {
            bytes = write(sockfd,message+sent,total-sent);
            if (bytes < 0)
                error("ERROR writing message to socket");
            if (bytes == 0)
                break;
            sent+=bytes;
        } while (sent < total);
    
        /* receive the response */
        memset(response,0,sizeof(response));
        total = sizeof(response)-1;
        received = 0;
        do {
            bytes = read(sockfd,response+received,total-received);
            if (bytes < 0)
                error("ERROR reading response from socket");
            if (bytes == 0)
                break;
            received+=bytes;
        } while (received < total);
    
        if (received == total)
            error("ERROR storing complete response from socket");
    
        /* close the socket */
        close(sockfd);
    
        /* process response */
        printf("Response:\n%s\n",response);
    
        free(message);
        return 0;
    }
    

    这篇关于做一个HTTP POST和消费的响应简单的C例子的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆