应用层的功能
负责应用程序间的沟通来制定协议,通俗的来讲就是应用层会借助TCP、UDP协议在各种各样的程序之间传递数据(邮件、文件等等),这时候像应用层协议就可以规定这些数据的格式要满足什么样。
常见应用层协议:(带*要熟知)
–基于TCP的应用层协议 | –基于UDP的应用层协议 |
---|---|
*简单电子邮件传输协议(SMTP) | *动态主机配置协议(DHCP) |
*文件传输协议(FTP) | *域名解析协议(DNS) |
*网络远程访问协议(Telnet) | 网络文件系统(NFS)、简单文件传输协议(TFTP)启动协议(BOOTP) |
*超文本传输协议(HTTP) |
认识HTTP协议
1、http请求:
- 首行:方法+url+版本号
- Header:表示请求的属性,是一个个键值对(键:值),每个键值对用\n隔开,遇到空行Header就结束了。
- Body:空行后面的内容,如果存在Body首先方法应该是POST方法,而且对应Header中会有一个字段Content-Length,这个字段表示Body的长度
2、http响应
- 首行:版本号+状态码+状态码解释
这里说到了状态码,那就讲一下:
状态码 类别 原因 1xx 信息性状态码 接受的请求正在处理 2xx 成功状态码 请求正常处理完毕 3xx 重定向状态码 需要进行附加操作以完成请求 4xx 客户端错误状态码 服务器无法处理请求 5xx 服务器错误状态码 服务器处理请求错误 常见的错误码:200(表示请求正常处理OK) 404(NOT FOUND)403(Forbidden) 302(Redirect) 504(Bad Gateway不可用) 502(超时)
- Header:请求的属性,也是键值对,键值对之间用\n分隔,遇到空行表示Header结束。
- Body:空行后面的内容就是Body部分,如果存在Body对应Header中会有一个字段Content-Length,这个字段表示Body的长度,如果服务器返回一个html页面,那么页面内容就在body中。
3、常见的HTTP方法
方法 | 功能 | 支持的协议版本 |
---|---|---|
GET | 获取资源(表示从服务器上获取) | 1.0、1.1 |
POST | 传输实体主体 | 1.0、1.1 |
PUT | 传输文件 | 1.0、1.1 |
GET方法和POST方法最大的区别在于GET方法没有Body部分,所以Header中就没有Content-Length和Content-Type这两个键值对。
4、HTTP常见Header
- Content-Type:数据类型(text/html等)
- Content-Length:Body的长度
- Host:客户端告知服务器,所请求的资源在那个主机的哪个端口上。
- User-Agent:声明用户的操作系统和浏览器版本信息
- Cookie:用于在客户端存储少量信息,(比如说访问需要用户登录的界面),通常用于实现会话的功能。
5、简单版本的Http服务器
此服务器中构造了响应,打印“hello world”,
#include<stdio.h>
#include<sys/socket.h>
#include<string.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<unistd.h>
#include<stdlib.h>
typedef struct sockaddr_in sockaddr_in;
typedef struct sockaddr sockaddr;
int main(int argc,char* argv[]){
if(argc!=3){
perror("Usage [ip][port]\n");
return 1;
}
int sock=socket(AF_INET,SOCK_STREAM,0);
if(sock<0){
perror("sock\n");
return 2;
}
sockaddr_in local;
local.sin_family=AF_INET;
local.sin_addr.s_addr=inet_addr(argv[1]);
local.sin_port=htons(atoi(argv[2]));
int ret=bind(sock,(sockaddr*)&local,sizeof(local));
if(ret<0){
printf("bing fail\n");
return 3;
}
ret=listen(sock,5);
if(ret<0){
perror("listen\n");
return 3;
}
//while
while(1){
sockaddr_in peer;
socklen_t len=sizeof(peer);
int new_sock=accept(sock,(sockaddr*)&peer,&len);
if(new_sock<0){
perror("accept\n");
continue;
}
char in_buf[1024*10]={0};
ssize_t read_size=read(new_sock,in_buf,sizeof(in_buf)-1);
if(read_size<0){
perror("read\n");
return 1;
}
else if(read_size==0){
close(new_sock);
}
in_buf[read_size]=0;
printf("client say:%s\n",in_buf);
char out_buf[1024]={0};
const char* hello="<h1>hello world</h1>";
sprintf(out_buf,"HTTP/1.0 200 OK\nContent-Length:%lu\n\n%s",strlen(hello),hello);//此处是将参数二作为构造的HTTP响应,格式化的写进new_sock中
write(new_sock,out_buf,strlen(out_buf));
}
}