我想创建一个非常简单的C应用程序,它可以执行HTTP post.它需要几个参数,并使用这些参数来构造URL.我只想做一个简单的HTTP POST,并在不使用curl的情况下获得响应(库没有也不会安装在需要运行的机器上).
伪代码:
过程2参数
在生成的URL上进行发布
消费react
我的谷歌搜索和其他搜索在这个问题上没有任何结果.
我想创建一个非常简单的C应用程序,它可以执行HTTP post.它需要几个参数,并使用这些参数来构造URL.我只想做一个简单的HTTP POST,并在不使用curl的情况下获得响应(库没有也不会安装在需要运行的机器上).
伪代码:
过程2参数
在生成的URL上进行发布
消费react
我的谷歌搜索和其他搜索在这个问题上没有任何结果.
消息有一个标题部分和一个消息体,两部分之间用空行隔开.即使没有消息体,也总是需要空白行.标头以一个命令开头,并包含由冒号和空格分隔的其他键值对行.如果有一个消息体,它可以是任何你想要的东西.
页眉中的行和页眉末尾的空行必须以Carraige回车符和换行符对结束(请参见HTTP header line break style),这就是为什么这些行的末尾有\r\n.
URL的格式为http://主机:港口城市/path?query_string
向网站提交请求主要有两种方式:
GET:查询字符串是可选的,但如果指定,则必须相当短.因此,标题可能只是GET命令,而不是其他命令.示例消息可以是:
GET /path?query_string HTTP/1.0\r\n
\r\n
POST:通常在查询字符串中的内容在消息体中.因此,标头需要包括Content-Type:和Content-Length:属性以及POST命令.示例消息可能是:
POST /path HTTP/1.0\r\n
Content-Type: text/plain\r\n
Content-Length: 12\r\n
\r\n
query_string
因此,为了回答您的问题:如果您想发布到的URL是http://api.somesite.com/apikey=ARG1&command=ARG2,那么就没有正文或查询字符串,因此也没有发布的理由,因为消息正文中没有内容,所以内容类型和内容长度中没有内容:
我想如果你真的想发的话,你可以发.在这种情况下,您的消息如下所示:
POST /apikey=ARG1&command=ARG2 HTTP/1.0\r\n
\r\n
因此,要发送消息,C程序需要:
发送和接收呼叫不一定发送/接收您给它们的所有数据——它们将返回实际发送/接收的字节数.这取决于你在一个循环中呼叫他们,并发送/接收消息的其余部分.
在这个示例中,我没有做任何类型的真正的错误判断——当出现故障时,我只是退出程序.如果对你有效,请告诉我:
#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 主机ent, get主机byname */
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 港口城市no = 80;
char *主机 = "api.somesite.com";
char *message_fmt = "POST /apikey=%s&command=%s HTTP/1.0\r\n\r\n";
struct 主机ent *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 = get主机byname(主机);
if (server == NULL) error("ERROR, no such 主机");
/* fill in the structure */
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_港口城市 = htons(港口城市no);
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");
/* 发送请求 */
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 the number of received bytes is the total size of the
* array then we have run out of space to store the response
* and it hasn't all arrived yet - so that's a bad thing
*/
if (received == total)
error("ERROR storing complete response from socket");
/* 合上插座 */
close(sockfd);
/* process response */
printf("Response:\n%s\n",response);
return 0;
}
就像另一个答案指出的那样,4096个字节不是非常大的响应.我随机 Select 了这个数字,因为我认为对您的请求的响应会很短.如果它可以很大,你有两个 Select :
回答 comments 中提出的问题的其他信息:
如果要在消息正文中发布数据,该怎么办?然后,您确实需要包括Content-Type:和Content-Length:标头.content-length:是分隔标题和正文的空行之后所有内容的实际长度.
下面是一个获取以下命令行参数的示例:
所以,对于最初的问题,你会运行:
a.out api.somesite.com 80 GET "/apikey=ARG1&command=ARG2"
对于你在 comments 中提出的问题:
a.out api.somesite.com 80 POST / "name=ARG1&value=ARG2" "Content-Type: application/x-www-form-urlencoded"
以下是代码:
#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 主机ent, get主机byname */
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 港口城市no = atoi(argv[2])>0?atoi(argv[2]):80;
char *主机 = strlen(argv[1])>0?argv[1]:"local主机";
struct 主机ent *server;
struct sockaddr_in serv_addr;
int sockfd, bytes, sent, received, total, message_size;
char *message, response[4096];
if (argc < 5) { puts("Parameters: <主机> <港口城市> <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 = get主机byname(主机);
if (server == NULL) error("ERROR, no such 主机");
/* fill in the structure */
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_港口城市 = htons(港口城市no);
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");
/* 发送请求 */
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 the number of received bytes is the total size of the
* array then we have run out of space to store the response
* and it hasn't all arrived yet - so that's a bad thing
*/
if (received == total)
error("ERROR storing complete response from socket");
/* 合上插座 */
close(sockfd);
/* process response */
printf("Response:\n%s\n",response);
free(message);
return 0;
}