网络原理(二)——应用层

时间:2022-07-24
本文章向大家介绍网络原理(二)——应用层,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

应用层协议

负责应用层程序之间的数据沟通(应用层的协议是程序员自己定制的)

自定制协议

只要保证, 一端发送时构造的数据, 在另一端能够正确的进行解 析, 就是ok的. 这种约定, 就是 应用层协议。

自定制协议中的相关概念:
  • 序列化:将数据对象按照指定协议组织成为可持久化存储/数据传输的二进制数据串
  • 反序列化:将二进制数据串按照指定协议进行解析得到各个数据对象

HTTP协议

HTTP协议即超文本传输协议。

认识URL

我们常说的网址就是URL(统一资源定位符)

协议方案名:用户名:用户密码@服务器地址:服务器端口号/请求的资源路径名称?查询字符串#片段标识符

  • 域名:一种IP地址的表示方式–但是域名还是需要转换为服务器的IP地址
  • 查询字符串:客户端给服务端提交的数据,需要进行url编码(对特殊字符进行转)由一个个键值对组成,并且键值对是以key=val的形式,键值对之间以&进行间隔
  • #片段标识符:一个标签,直接转到网页的某个位置
URL的转码和解码
  • urlencode:将特殊字符的每一个字节都转换为16进制数字的字符串,并且为了表示两个字符串经过了url编码,因此在编码后的字符前加上%符号。
  • urldecode:当在查询字符串中遇到%符号,则认为紧跟其后的两个字符串进行解码,将两个字符转换为数字,第一个数字左移4位,加上第二个字符

HTTP协议格式

HTTP请求
  • 首行: [方法] + [url] + [版本]
  • Header: 请求的属性, 冒号分割的键值对;每组属性之间使用n分隔;遇到空行表示Header部分结束
  • Body: 空行后面的内容都是Body. Body允许为空字符串. 如果Body存在, 则在Header中会有一个Content-Length属性来标识Body的长度;
HTTP响应
  • 首行: [版本号] + [状态码] + [状态码解释]
  • Header: 请求的属性, 冒号分割的键值对;每组属性之间使用n分隔;遇到空行表示Header部分结束
  • Body: 空行后面的内容都是Body. Body允许为空字符串. 如果Body存在, 则在Header中会有一个Content-Length属性来标识Body的长度; 如果服务器返回了一个html页面, 那么html页面内容就是在body中.

HTTP的方法

HTTP的状态码

常用状态码及解释:

200响应正确 301永久重定向 302临时重定向 303查看其他地址 403拒绝请求 404请求的资源没有找到 500服务器内部错误 502网关错误(代理或者网关返回)

HTTP常见Header

  • Content-Type: 数据类型(text/html等)
  • Content-Length: Body的长度
  • Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;
  • User-Agent: 声明用户的操作系统和浏览器版本信息;
  • referer: 当前页面是从哪个页面跳转过来的;
  • location: 搭配3xx状态码使用, 告诉客户端接下来要去哪里访问;
  • Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能;

模拟实现HTTP服务器

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 

int main(int argc, char* argv[]) {
  if (argc != 3) {
    printf("usage: ./server [ip] [port]n");
    return 1;
    }
  int fd = socket(AF_INET, SOCK_STREAM, 0);
  if (fd < 0) {
    perror("socket");
    return 1;
  }
  struct sockaddr_in addr;
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = inet_addr(argv[1]);
  addr.sin_port = htons(atoi(argv[2]));
 
  int ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
  if (ret < 0) {
    perror("bind");
    return 1;
  }
  ret = listen(fd, 10);
  if (ret < 0) {
    perror("listen");
    return 1;
  } 
  for (;;) {
    struct sockaddr_in client_addr;
    socklen_t len;
    int client_fd = accept(fd, (struct sockaddr*)&client_addr, &len);
    if (client_fd < 0) {
      perror("accept");
      continue;
    }
    char input_buf[1024 * 10] = {0}; 
    ssize_t read_size = read(client_fd, input_buf, sizeof(input_buf) - 1);
    if (read_size < 0) {
      return 1;
    }
    printf("[Request] %s", input_buf);
    char buf[1024] = {0};
    const char* hello = "<h1>hello world</h1>";
    sprintf(buf, "HTTP/1.0 200 OKnContent-Length:%lunn%s", strlen(hello), hello);
    write(client_fd, buf, strlen(buf));
  }
  return 0;
}
运行结果:
浏览器访问结果