메시지에는 빈 줄로 구분 된 헤더 부분과 메시지 본문이 있습니다. 메시지 본문이 없더라도 빈 줄은 항상 필요합니다. 헤더는 명령으로 시작하며 콜론과 공백으로 구분 된 추가 키 값 쌍 행이 있습니다. 메시지 본문이있는 경우 원하는 모든 것이 될 수 있습니다.
헤더의 줄과 헤더 끝에있는 빈 줄은 carraige 리턴 및 줄 바꿈 쌍 ( HTTP 헤더 줄 바꿈 스타일 참조)으로 끝나야 하므로 해당 줄의 끝에 \ r \ n이 있습니다.
URL의 형식은 다음과 같습니다. http://host:port/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
따라서 귀하의 질문에 답하기 위해 : POST에 관심이있는 URL이 http://api.somesite.com/apikey=ARG1&command=ARG2 이면 본문이나 쿼리 문자열이 없기 때문에 POST 할 이유가 없습니다. 메시지 본문에 넣을 것이 없으므로 Content-Type : 및 Content-Length에 넣을 것이 없습니다.
정말로 원한다면 게시 할 수있을 것 같습니다. 이 경우 메시지는 다음과 같습니다.
POST /apikey=ARG1&command=ARG2 HTTP/1.0\r\n
\r\n
따라서 메시지를 보내려면 C 프로그램이 다음을 수행해야합니다.
- 소켓 생성
- IP 주소 조회
- 소켓을 열다
- 요청을 보내다
- 응답을 기다리다
- 소켓을 닫으십시오
전송 및 수신 호출은 사용자가 제공 한 모든 데이터를 반드시 전송 / 수신하는 것은 아닙니다. 실제로 전송 / 수신 된 바이트 수를 반환합니다. 루프에서 호출하고 나머지 메시지를 보내고받는 것은 사용자에게 달려 있습니다.
이 샘플에서 내가하지 않은 것은 일종의 실제 오류 검사입니다. 무언가가 실패하면 프로그램을 종료합니다. 그것이 당신을 위해 작동하는지 알려주십시오.
#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[])
{
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); }
sprintf(message,message_fmt,argv[1],argv[2]);
printf("Request:\n%s\n",message);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) error("ERROR opening socket");
server = gethostbyname(host);
if (server == NULL) error("ERROR, no such host");
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);
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);
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(sockfd);
printf("Response:\n%s\n",response);
return 0;
}
지적한 다른 답변과 마찬가지로 4096 바이트는 그다지 큰 응답이 아닙니다. 귀하의 요청에 대한 응답이 짧을 것이라고 가정하여 무작위로 해당 번호를 선택했습니다. 크기가 클 수있는 경우 두 가지 선택이 있습니다.
- 응답에서 Content-Length : 헤더를 읽은 다음 전체 응답을 저장할 충분한 메모리를 동적으로 할당합니다.
- 조각이 도착하면 파일에 응답을 작성합니다.
댓글에 묻는 질문에 대한 추가 정보 :
메시지 본문에 데이터를 POST하려면 어떻게해야합니까? 그런 다음 Content-Type : 및 Content-Length : 헤더를 포함해야합니다. Content-Length : 헤더와 본문을 구분하는 빈 줄 뒤의 모든 항목의 실제 길이입니다.
다음은 다음 명령 줄 인수를 사용하는 샘플입니다.
- 주최자
- 포트
- 명령 (GET 또는 POST)
- 경로 (쿼리 데이터 제외)
- 쿼리 데이터 (GET의 경우 쿼리 문자열에, POST의 경우 본문에 입력)
- 헤더 목록 (Content-Length : POST를 사용하는 경우 자동)
따라서 원래 질문에 대해 다음을 실행합니다.
a.out api.somesite.com 80 GET "/apikey=ARG1&command=ARG2"
그리고 코멘트에서 묻는 질문에 대해 실행합니다.
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 hostent, gethostbyname */
void error(const char *msg) { perror(msg); exit(0); }
int main(int argc,char *argv[])
{
int i;
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); }
message_size=0;
if(!strcmp(argv[3],"GET"))
{
message_size+=strlen("%s %s%s%s HTTP/1.0\r\n");
message_size+=strlen(argv[3]);
message_size+=strlen(argv[4]);
if(argc>5)
message_size+=strlen(argv[5]);
for(i=6;i<argc;i++)
message_size+=strlen(argv[i])+strlen("\r\n");
message_size+=strlen("\r\n");
}
else
{
message_size+=strlen("%s %s HTTP/1.0\r\n");
message_size+=strlen(argv[3]);
message_size+=strlen(argv[4]);
for(i=6;i<argc;i++)
message_size+=strlen(argv[i])+strlen("\r\n");
if(argc>5)
message_size+=strlen("Content-Length: %d\r\n")+10;
message_size+=strlen("\r\n");
if(argc>5)
message_size+=strlen(argv[5]);
}
message=malloc(message_size);
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",
strlen(argv[4])>0?argv[4]:"/",
strlen(argv[5])>0?"?":"",
strlen(argv[5])>0?argv[5]:"");
else
sprintf(message,"%s %s HTTP/1.0\r\n",
strlen(argv[3])>0?argv[3]:"GET",
strlen(argv[4])>0?argv[4]:"/");
for(i=6;i<argc;i++)
{strcat(message,argv[i]);strcat(message,"\r\n");}
strcat(message,"\r\n");
}
else
{
sprintf(message,"%s %s HTTP/1.0\r\n",
strlen(argv[3])>0?argv[3]:"POST",
strlen(argv[4])>0?argv[4]:"/");
for(i=6;i<argc;i++)
{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");
if(argc>5)
strcat(message,argv[5]);
}
printf("Request:\n%s\n",message);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) error("ERROR opening socket");
server = gethostbyname(host);
if (server == NULL) error("ERROR, no such host");
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);
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);
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(sockfd);
printf("Response:\n%s\n",response);
free(message);
return 0;
}