HTTP
实现http客户端程序
基础
HTTP使用TCP连接
HTTP报文:
实现
域名到ip地址转换(dns) 直接调用api进行转换比较简单:
char * host_to_ip(const char* hostname)
{
struct hostent *host_entry = gethostbyname(hostname);
if(host_entry)
{
return inet_ntoa(*(struct in_addr*)*host_entry -> h_addr_list);
}
return NULL;
}
host_entry存储了dns请求的接收,从中取出第一个ip地址并将点分十进制转换为字符串返回
创建TCP套接字(建立连接) posix api创建
int http_create_socket(char *ip)
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in sin = {0};
sin.sin_family = AF_INET;
sin.sin_port = htons(80);
sin.sin_addr.s_addr = inet_addr(ip);
if(0 != connect(sockfd, (struct sockaddr*)&sin, sizeof(struct sockaddr_in)))
{
return -1;
}
fcntl(sockfd, F_SETFL, O_NONBLOCK);
return sockfd;
}
fcntl(sockfd, F_SETFL, O_NONBLOCK);这个函数用于设置该套接字io为非阻塞
通过套接字向目标网站请求资源(select)
char * http_send_request(const char *hostname, const char *resource) {
char *ip = host_to_ip(hostname); //
int sockfd = http_create_socket(ip);
char buffer[BUFFER_SIZE] = {0};
sprintf(buffer,
"GET %s %s\r\n\
Host: %s\r\n\
%s\r\n\
\r\n",
resource, HTTP_VERSION,
hostname,
CONNECTION_TYPE
);
send(sockfd, buffer, strlen(buffer), 0);
//select
fd_set fdread;
FD_ZERO(&fdread);
FD_SET(sockfd, &fdread);
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
char *result = malloc(sizeof(int));
memset(result, 0, sizeof(int));
while (1) {
int selection = select(sockfd+1, &fdread, NULL, NULL, &tv);
if (!selection || !FD_ISSET(sockfd, &fdread)) {
break;
} else {
memset(buffer, 0, BUFFER_SIZE);
int len = recv(sockfd, buffer, BUFFER_SIZE, 0);
if (len == 0) { // disconnect
break;
}
result = realloc(result, (strlen(result) + len + 1) * sizeof(char));
strncat(result, buffer, len);
}
}
return result;
}
select部分: 首先根据套接字初始化fread来监听io,如果有消息到来就置为1,调用select函数: select(sockfd, &rset, &wset, *eset, *tv); &rset位置表示读监听io &wset位置表示写监听io &eset位置表示错误监听io(断开或者其他) tv为轮询间隔时间 select函数内部轮询监听这几个io,有置1就说明有信息需要处理,就返回然后处理信息 断开连接的话返回0,所以if (!selection || !FD_ISSET(sockfd, &fdread))可以有效控制连接断开的break 正常时返回收到的结果result
附main函数
int main(char argc, char*argv[])
{
if(argc <3)
{
return -1;
}
char *response = http_send_request(argv[1], argv[2]);
printf("response: %s\n", response);
free(response);
return 1;
}