在浏览器与服务器建立连接发送请求时,首先在socket基础上建立TCP连接,发送http请求,服务器在停车票连接上,返回http协议response。
1.域名翻译为IP地址
除了使用DNS请求域名外,还可以使用gethostbyname();
struct hostent* host_entry = gethostbyname(hostname);
返回一个实例,包括主机名,字段长度,IP列表。
struct hostent{
char *h_name; //地址正式名称
char *h_aliases; //地址预备名称指针
short h_addrtype; //地址类型
short h_length; //地址比特长度
char **h_addr_list; // 主机网络地址指针
};
将点分十进制转化为字符串指针
//255.255.255.255 点分十进制
inet_ntoa(*(struct in_addr*)*host_entry->h_addr_list);
2.tcp socket连接
建立socket句柄 sockfd 为file descriptor 看做一个文件,在socket上收发,相当于对一个文件进行读写。
SOCK_STREAM 为TCP连接
SOCK_DGRAM为UDP连接
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);
connect(sockfd,(struct sockaddr*)&sin,sizeof(struct sockaddr_in))); //连接服务器
fcntl(sockfd,F_SETFL,O_NONBLOCK);
struct sockaddr_in结构如下
struct sockaddr_in{
sin_family //地址族协议
sin_port
struct in_addr sin_addr;//地址
}
struct in_addr{
in_addr_t s_addr;
}
阻塞接收时,会一直等待到数据到来,非阻塞接收时,无数据则返回
inet_addr();//将有效字符串转化为32位二进制网络字节序的IPV4地址
fcntl(FD,CMD.LOCK);//函数用于改变fd指定文件的特征
//cmd 为F_SETFL时,lock位可以为O_APPENO,O_NONBLOCK,O_ASYNC
3.发送请求
按照HTTP协议,将【请求资源、版本号】,【域名】,【连接方式】整合到一个char【】中,进行请求发送。
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,
CONNETION_TYPE
);
send(sockfd, buffer, strlen(buffer), 0);
fd_set fdread; //io组是否有数据可读的标志组
FD_ZERO(&fdread);
FD_SET(sockfd, &fdread); // jiang fd 加入到集合中 一起判断
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);
//select(IO数量+1,可读集合,可写,出错,轮询时间);
if (!selection || !FD_ISSET(sockfd, &fdread)) {
//FD_ISSET 判断fd是否在fd_set中,避免数据出错 检测到返回真
break;
} else {
memset(buffer, 0, BUFFER_SIZE);
int len = recv(sockfd, buffer, BUFFER_SIZE, 0);
if (len == 0) { //为对方关闭
break;
}
result = realloc(result, (strlen(result) + len + 1) * sizeof(char));
strncat(result, buffer, len);
}
}
return result;
}
struct timeval{
time_t tv_sec; //sec
suseconds_t tv_usec;//毫sec
}