目录
1 域名解析
2 如何实现万维网服务器?
2.1 HTTP 的操作过程
2.2 万维网服务器实现
域名解析gethostbyname函数
主机结构在
struct hostent {
char *h_name; /* 官方域名 */
char **h_aliases; /* 别名*/
int h_addrtype; /* 地址族(地址类型) */
int h_length; /* 地址长度 */
char **h_addr_list; /* 地址列表 */
}
#define h_addr h_addr_list[0] /* 实现向后兼容性 */
结构的成员包括:
h_name :主机的正式名称
h_aliases:主机的备用名称数组,以 NULL 结尾指针
h_addrtype:地址类型;(AF_INET或AF_INET6)
h_length:地址的长度(以字节为单位)
h_addr_list:指向主机网络地址的指针数组(按网络字节顺序),由 NULL 指针终止
h_addr h_addr_list:中的第一个地址,以实现向后兼容性
示例
#include
#include
#include
#include
#include
int main(int argc, char *argv[])
{
int i;
if(argc < 2){
printf("%s \n", argv[0]);
exit(0);
}
struct hostent *host = gethostbyname(argv[1]);
for(i = 0; host->h_aliases[i] != NULL; i++){
printf("%s\n", host->h_aliases[i]);
}
printf("Address type:%s\n",
host->h_addrtype == AF_INET ? "AF_INET":"AF_INET6");
for(i = 0; host->h_addr_list[i] != NULL; i++){
printf("IP address %d:%s\n", i, inet_ntoa(*(struct in_addr *)host->h_addr_list[i]));
}
endhostent(); //释放创建出的地址
return 0;
}
实现效果
HTTP 规定:在 HTTP 客户与 HTTP 服务器之间的每次交互,都由一个 ASCII 码串构成的请求和一个类似的通用互联网扩充,即“类MIME (MIME-like)”的响应组成。
HTTP 报文通常都使用 TCP 连接传送。
http连接过程
html解释型语言
home
Hello World!
nginx
打开home.html(firefox ./home.html)
nc命令实现步骤
HTTP/1.1 200 OK
Content-Type: text/html
home
Hello World!
nginx
代码实现步骤
home.html
server name
文档标题
Hello World!
http-head.txt
HTTP/1.1 200 OK
Content-Type: text/html
Connection: close
服务代码
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define PORT 80
#define BACKLOG 5
#define HTTPFILE "http-head.txt"
#define HTMLFILE "home.html"
int ClientHandle(int newfd);
int main(int argc, char *argv[])
{
int fd, newfd;
struct sockaddr_in addr;
/*创建套接字*/
fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd < 0){
perror("socket");
exit(0);
}
int opt = 1;
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *) &opt, sizeof(opt) ))
perror("setsockopt");
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = 0;
/*绑定通信结构体*/
if(bind(fd, (struct sockaddr *)&addr, sizeof(addr) ) == -1){
perror("bind");
exit(0);
}
/*设置套接字为监听模式*/
if(listen(fd, BACKLOG) == -1){
perror("listen");
exit(0);
}
/*接受客户端的连接请求,生成新的用于和客户端通信的套接字*/
newfd = accept(fd, NULL, NULL);
if(newfd < 0){
perror("accept");
exit(0);
}
ClientHandle(newfd);
close(fd);
return 0;
}
int ClientHandle(int newfd){
int file_fd = -1;
char buf[BUFSIZ] = {};
int ret;
do {
ret = recv(newfd, buf, BUFSIZ, 0);
}while(ret < 0 && errno == EINTR); //小于0并且信号中断
if(ret < 0){
perror("recv");
exit(0);
}else if(ret == 0){
close(newfd);
return 0;
}else{
printf("=====================================\n");
printf("%s", buf);
fflush(stdout);
}
bzero(buf, ret);
file_fd = open(HTTPFILE, O_RDONLY); //http文件
if(file_fd < 0){
perror("open");
exit(0);
}
ret = read(file_fd, buf, BUFSIZ);
printf("%s\n", buf);
send(newfd, buf, ret, 0);
close(file_fd);
bzero(buf, ret);
file_fd = open(HTMLFILE, O_RDONLY); //html文件
if(file_fd < 0){
perror("open");
exit(0);
}
ret = read(file_fd, buf, BUFSIZ);
printf("%s\n", buf);
send(newfd, buf, ret, 0);
close(file_fd);
close(newfd);
return 0;
}
1.模拟实现http服务器,并使用浏览器访问。提交浏览器访问你http服务器的截图