应用层 - HTTP 重点!!!

本文详细探讨了应用层协议的重要性和实现,特别是聚焦于HTTP协议。内容包括HTTP协议的无状态特性、常见方法如GET和POST的区别、状态码的意义以及Header的使用。此外,还介绍了URL编码、最简单的HTTP服务器的实现,并强调了Cookie在会话管理中的作用。
摘要由CSDN通过智能技术生成

注意!!注意!!注意!!
本篇博客是:

  • 网络编程的理论基础
  • 是一个服务器开发程序员的重要基本功
  • 是整个Linux课程中的重点和难点
  • 也是各大公司面试笔试的核心考点

应用层

我们程序员写的一个个解决我们实际问题,满足我们日常需求的网络程序,都在应用层。

再谈“协议”

协议是一种 “约定”. socket api的接口, 在读写数据时, 都是按 “字符串” 的方式来发送接收的. 如果我们要传输一些 “结构化的数据” 怎么办呢?

网络版计算机

例如, 我们需要实现一个服务器版的加法器. 我们需要客户端把要计算的两个加数发过去, 然后由服务器进行计算, 后再把结果返回给客户端。

约定方案一:

  • 客户端发送一个形如“1+1”的字符串
  • 这个字符串有两个操作符,都是整型
  • 两个数字之间会有一个字符是运算符, 运算符只能是 + ;
  • 数字和运算符之间没有空格

约定方案二:

  • 定义结构体来表示我们需要交互的信息;
  • 发送数据时将这个结构体按照一个规则转换成字符串, 接收到数据的时候再按照相同的规则把字符串转 化回结构体;
  • 这个过程叫做 “序列化” 和 "反序列化
//proto.h定义通信的结构体
typedef struct Request
{
	int a;
	int b;
}Request;

typedef struct Response
{
	int sum;
};

//client.c 客户端核心代码
Request request;
Response response;

scanf("%d %d", &request.a, &response.b);
write(fd, request, sizeof(Request));
read(fd, response sizeof(Response));

//server.c 服务器核心代码
Request request; 
read(client_fd, &request, sizeof(request)); 
Response response; 
response.sum = request.a + request.b;
write(client_fd, &response, sizeof(response));

无论我们采用方案一, 还是方案二, 还是其他的方案, 只要保证, 一端发送时构造的数据, 在另一端能够正确的进行解 析, 就是ok的. 这种约定, 就是 应用层协议

HTTP协议(超文本传输协议)

  • 无状态的
  • 应用层
  • 可靠
  • 面向字节流
  • 底层是TCP协议,正常通信前要进行三次握手
认识URL

平时我们俗称的“网址”,其实就是说的URL
在这里插入图片描述

urlencode和urldecode

/ ? : 等这样的字符, 已经被url当做特殊意义理解了. 因此这些字符不能随意出现.
比如, 某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义.

转义的规则如下:
将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY 格式 ,"+" 被转义成了 “%2B”

HTTP协议格式

在这里插入图片描述
在这里插入图片描述

HTTP的方法

在这里插入图片描述
其中最常用的我就是GET和POST方法
GET和POST的区别?

  • GET在url传参,POST在正文传参
  • url的长度是有限制的,正文传参是无限制的
  • GET在传参时,把数据暴露在外边,而POST不会把信息暴露在外边,POST比GET更私密
HTTP的状态码

在这里插入图片描述

最常见的状态码,比如200(ok)404(Not Found0)403(Forbidden)302(Rediret,重定向)504(Bad Gateway)

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>
 
void Usage()
 {  
 	printf("usage: ./server [ip] [port]\n");
 }
 
int main(int argc, char* argv[])
 {
 	  if (argc != 3) 
 	  	{
 	  		    Usage();
 	  		    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 OK\nContent-Length:%lu\n\n%s", strlen(hello), hello); 
	        write(client_fd, buf, strlen(buf));      						  
	  } 
   return 0; 
   } 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值