http通信过程:
1、URL自动解析
HTTP URL包含了用于查找某个资源的足够信息,基本格式如下:HTTP://host[“:”port][abs_path],其中HTTP表示桶盖HTTP协议来定位网络资源;host表示合法的主机域名或IP地址,port指定一个端口号,缺省80;abs_path指定请求资源的URI;如果URL中没有给出abs_path,那么当它作为请求URI时,必须以“/”的形式给出,通常这个工作浏览器自动帮我们完成。
例如:输入www.163.com;浏览器会自动转换成:HTTP://www.163.com/
2、获取IP,建立TCP连接
浏览器地址栏中输入"HTTP://www.xxx.com/"并提交之后,首先它会在DNS本地缓存表中查找,如果有则直接告诉IP地址。如果没有则要求网关DNS进行查找,如此下去,找到对应的IP后,则返回会给浏览器。( DNS域名解析分为迭代式和递归式。迭代式降低了根域的压力。其方法使用的比较多。)
当获取IP之后,就开始与所请求的Tcp建立三次握手连接,连接建立后,就向服务器发出HTTP请求。 如图:
3、客户端浏览器向服务器发出HTTP请求
一旦建立了TCP连接,Web浏览器就会向Web服务器发送请求命令,接着以头信息的形式向Web服务器发送一些别的信息,之后浏览器发送了一空白行来通知服务器,它已经结束了该头信息的发送。
4、Web服务器应答,并向浏览器发送数据
客户机向服务器发出请求后,服务器会客户机回送应答,
HTTP/1.1 200 OK
应答的第一部分是协议的版本号和应答状态码,正如客户端会随同请求发送关于自身的信息一样,服务器也会随同应答向用户发送关于它自己的数据及被请求的文档。
Web服务器向浏览器发送头信息后,它会发送一个空白行来表示头信息的发送到此为结束,接着,它就以Content-Type应答头信息所描述的格式发送用户所请求的实际数据
5、Web服务器关闭TCP连接
一般情况下,一旦Web服务器向浏览器发送了请求数据,它就要关闭TCP连接,然后如果浏览器或者服务器在其头信息加入了这行代码 :Connection:keep-alive
TCP连接在发送后将仍然保持打开状态,于是,浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽。
HTTP通信代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <sys/stat.h>
int SendHead(int c,char* path,int status)
{
char buff[1024] = "HTTP/1.1"; //版本
sprintf(buff+strlen(buff),"%d",status);
switch(status)
{
case 200:
strcat(buff," ok\n\r");
break;
case 404:
strcat(buff," Not Found\n\r");
break;
case 503:
strcat(buff," Service Unavailable\n\r");
default:
printf("error");
return 0;
}
strcat(buff,"Server:MYHTTP/1.0\n\r");
strcat(buff,"Connect-Length:");
struct stat st;
stat(path,&st);
sprintf(buff+strlen(buff),"%d",st.st_size);
strcat(buff,"\n\r");
strcat(buff,"Content-Type: text/html;charset=utf-8\n\r");
strcat(buff,"\n\r");
send(c,buff,strlen(buff),0);
return 1;
}
void SendClient(int c,char* buff)
{
/*GET/INDEX.HTML HTTP/1.1 */
int status = 200;
char *p = strtok(buff," ");
p = strtok(NULL," ");
char path[128] = "/var/www/html";
strcat(path,p);
int fd = open(path,O_RDONLY);
if(fd == -1)
{
status = 404;
fd = open("/var/www/html/404.html",O_RDONLY);
if(fd == -1)
{
return;
}
//status = 404;
}
if(!SendHead(c,path,status))
{
close(fd);
return;
}
while(1)
{
char file_buff[128] = {0};
int n = read(fd,file_buff,127);
if(n <= 0)
{
close(fd);
break;
}
send(c,file_buff,n,0);
}
}
int main()
{
int listenfd = socket(AF_INET,SOCK_STREAM,0);
assert(listenfd != -1);
struct sockaddr_in ser,cli;
memset(&ser,0,sizeof(ser));
ser.sin_family = AF_INET;
ser.sin_port = htons(8080);
ser.sin_addr.s_addr = inet_addr("192,168,1.154");
int res = bind(listenfd,(struct sockaddr*)&ser,sizeof(ser));
assert(res != -1);
listen(listenfd,5);//已经完成连接的最大个数
while(1)
{
int cli_len = sizeof(cli);
int c = accept(listenfd,(struct sockaddr*)&cli,&cli_len);
if(c < 0)
{
continue;
}
char buff[1024] = {0};
int n = recv(c,buff,1023,0);
if(n <= 0)
{
close(c);
continue;
}
printf("%s\n",buff);
SendClient(c,buff);
}
close(listenfd);
return 0;
}