文章目录
1. 浏览器与服务器通信过程
1.1 建立连接
浏览器与web服务器在应用层通信使用的是HTTP协议,而HTTP协议在传输层使用的是TCP协议。那么浏览器需要和web服务器三次握手建立连接后,才可以发送HTTP请求报文,服务器收到请求报文后,向浏览器回复HTTP应答报文。
1.2 使用端口
对于端口来讲,使用HTTP协议的程序一般默认使用80端口
1.3 长连接与短连接
浏览器服务器建立连接后,如果两次以上的请求复用同一个TCP连接,则称之为长连接。如果浏览器发送一次请求报文,服务器回复一次应答就断开连接,下次交互再重新进行三次握手建立连接,那么就被称作短连接。
使用长连接更好,可以减少网络中的同步报文,也使得服务器的响应速度变快
1.4 常见的 web 服务器
◼ Apache: 简单、速度快、性能稳定,并可做代理服务器使用
◼ IIS(Internet Information Server):安全性、强大、灵活
◼ Nginx:小巧而高效,可以做高效的负载均衡反向代理
◼ Tomcat:技术先进、性能稳定、免费
1.5 服务器与浏览器通信图解
2. HTTP请求
2.1 HTTP请求的部分内容
GET http://www.baidu.com/index.html HTTP/1.0
User-Agent:Wget/1.12(linux-gnu)
Host:www.baidu.com
Connection:close
图解
2.2 HTTP应答状态
2.2.1 HTTP应答部分内容
Http/1.0 200 OK
Server:BWS/1.0
Content-Lnegth:8024
Content-Type:text/html;charset=gbk
Set-Cookie:BAIDUID=A5B6C72D68CF639CE8896FD79A03FBDB:FG=1;expires=Wed,04-Jul-42 00:10:47 GMT;path=/;domain=.baidu.com
Via:1.0 localhost(squid/3.0 STABLE18)
图解
3. HTTP代码
3.1 代码示例1:发送ok
代码示例1
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<unistd.h>
5 #include<sys/socket.h>
6 #include<arpa/inet.h>
7 #include<netinet/in.h>
8 #include<pthread.h>
9 #include<fcntl.h>
10
11 int socket_init();
12 void *work_thread(void*arg);
13 int main()
14 {
15 int sockfd=socket_init();
16 if(sockfd==-1)
17 {
18 exit(1);
19 }
20 while(1)
21 {
22 struct sockaddr_in caddr;
23 int len=sizeof(caddr);
24 int c=accept(sockfd,(struct sockaddr*)&caddr,&len);
25 if(c<0)
26 {
27 continue;
28 }
29 pthread_t id;
30 pthread_create(&id,NULL,work_thread,(void*)c);
31 }
32 }
33
34 int send_http(int c,char*name)
35 {
36 if(name==NULL||c<=0)
37 {
38 return -1;
39 }
40 char http_head[512]={"HTTP/1.1 200 OK\r\n"};
41 strcat(http_head,"Server:myhttp\r\n");
42 strcat(http_head,"Content-Length:2\r\n");
43 strcat(http_head,"\r\n");
44 strcat(http_head,"ok");
45
46 send(c,http_head,strlen(http_head),0);
47 }
48
49 void* work_thread(void* arg)
50 {
51 int c=(int)arg;
52 while(1)
53 {
54 char buff[1024]={0};
55 int num=recv(c,buff,1023,0);
56 if(num<=0)
57 {
58 break;
59 }
60 printf("recv:\n%s\n",buff);
61 //解析报文,获得请求资源名称,组装应答报文发送数据
62 send_http(c,"filename");//测试
63 break;
64 }
65 close(c);
66 }
67
68 int socket_init()
69 {
70 int sockfd=socket(AF_INET,SOCK_STREAM,0);
71 if(sockfd==-1)
72 {
73 return -1;
74 }
75
76 struct sockaddr_in saddr;
77 memset(&saddr,0,sizeof(saddr));
78 saddr.sin_family=AF_INET;
79 saddr.sin_port=htons(80);//root
80 saddr.sin_addr.s_addr=inet_addr("0.0.0.0");
81
82 int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
83 if(res==-1)
84 {
85 printf("bind 80 err\n");
86 return -1;
87 }
88 res=listen(sockfd,5);
89 if(res==-1)
90 {
91 return -1;
92 }
93 return sockfd;
94 }
运行结果
ifconfig命令可以查看ip地址
3.2 代码示例1:发送ok
代码示例2
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<unistd.h>
5 #include<sys/socket.h>
6 #include<arpa/inet.h>
7 #include<netinet/in.h>
8 #include<pthread.h>
9 #include<fcntl.h>
10 #include<signal.h>
11
12 #define PATH "/home/maria/c215/20220806/web"
13 int socket_init();
14
15 void *work_thread(void*arg);
16
17 void sig_fun(int sig)
18 {
19 printf("浏览器异常关闭\n");
20 }
21
22 int main()
23 {
24 signal(SIGPIPE,sig_fun);
25 int sockfd=socket_init();
26 if(sockfd==-1)
27 {
28 exit(1);
29 }
30 while(1)
31 {
32 struct sockaddr_in caddr;
33 int len=sizeof(caddr);
34 int c=accept(sockfd,(struct sockaddr*)&caddr,&len);
35 if(c<0)
36 {
37 continue;
38 }
39 pthread_t id;
40 pthread_create(&id,NULL,work_thread,(void*)c);
41 }
42 }
43
44 void send_http_head(int c,int filesize)
45 {
46
47 char http_head[512]={"HTTP/1.1 200 OK\r\n"};
48 strcat(http_head,"Server:myhttp\r\n");
49 sprintf(http_head+strlen(http_head),"Content-Length:%d\r\n",filesize);
50 //strcat(http_head,"Content-Length:2\r\n");
51 strcat(http_head,"\r\n");
52 //strcat(http_head,"ok");
53
54 send(c,http_head,strlen(http_head),0);
55 }
56
57 int open_file(char*filename,int*psize)
58 {
59 char path[128]={PATH};
60 if(strcmp(filename,"/")==0)
61 {
62 strcat(path,"/index.html");
63 }
64 else
65 {
66 strcat(path,filename);
67 }
68 int fd=open(path,O_RDONLY);
69 if(fd==-1)//文件不存在
70 {
71 *psize=0;
72 return -1;
73 }
74
75 *psize=lseek(fd,0,SEEK_END);//文件大小
76 lseek(fd,0,SEEK_SET);
77 return fd;
78 }
79 int send_http(int c,char*name)
80 {
81 if(name==NULL||c<0)
82 {
83 return -1;
84 }
85 int filesize=0;
86 int fd=open_file(name,&filesize);
87 if(fd==-1)
88 {
89 send(c,"404",3,0);
90 return -1;
91 }
92 send_http_head(c,filesize);//发送报头
93 char data[1024]={0};
94 int num=0;
95 while((num=read(fd,data,1024))>0)
96 {
97 send(c,data,num,0);
98 }
99 close(fd);
100 }
101
102 char* get_name(char buff[])
103 {
104 if(buff==NULL)
105 {
106 return NULL;
107 }
108
109 char*ptr=NULL;
110 char*s=strtok_r(buff," ",&ptr);
111 if(strcmp(s,"GET")!=0)
112 {
113 return NULL;
114 }
115
116 s=strtok_r(NULL," ",&ptr);
117 return s;
118 }
119
120 void* work_thread(void* arg)
121 {
122 int c=(int)arg;
123 while(1)
124 {
125 char buff[1024]={0};
126 int num=recv(c,buff,1023,0);//接收浏览器发送过来的请求报文
127 if(num<=0)
128 {
129 break;
130 }
131 printf("recv:\n%s\n",buff);
132 //解析报文,获得请求资源名称,组装应答报文发送数据
133 char*filename=get_name(buff);
134 if(filename==NULL)
135 {
136 break;
137 }
138 int res=send_http(c,filename);//测试
139 if(res==-1)
140 {
141 break;
142 }
143
144 }
145 printf("close\n");
146 close(c);
147 }
148
149 int socket_init()
150 {
151 int sockfd=socket(AF_INET,SOCK_STREAM,0);
152 if(sockfd==-1)
153 {
154 return -1;
155 }
156
157 struct sockaddr_in saddr;
158 memset(&saddr,0,sizeof(saddr));
159 saddr.sin_family=AF_INET;
160 saddr.sin_port=htons(80);//root
161 saddr.sin_addr.s_addr=inet_addr("0.0.0.0");
162
163 int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
164 if(res==-1)
165 {
166 printf("bind 80 err\n");
167 return -1;
168 }
169 res=listen(sockfd,5);
170 if(res==-1)
171 {
172 return -1;
173 }
174 return sockfd;
175 }
运行结果