深入理解计算机网络之应用层详解

原地址:https://blog.csdn.net/qq_39412582/article/details/88543382

首先我们先来回顾一下OSI七层模型:

这里我们只介绍网络通信中重要的四层:

分层名称    功能    常用协议
应用层    针对特定应用的协议    FTP(文件传输有协议),DNS(域名系统)以及常见的 HTTP协议
传输层    管理两个节点之间的数据传输。负责可靠传输(确保数据被可靠的传送到目标地址)    TCP(传输控制协议)和UDP(用户数据报协议)
网络层    地址管理和路由选择(通过路由器寻址)    IP协议
数据链路层    互联设备之间的传送和识别数据帧    一般是一些硬件:网卡光纤等可见设备
应用层详解
HTTP协议即超文本传输协议。
说到HTTP协议,我们就离不开URL(统一资源定位符),没有它,HTTP是不完整的。
什么是URL?
https://www.google.com/search?q=URL&oq=URL&aqs=chrome..69i57j0l5.1240j0j8&sourceid=chrome&ie=UTF-8
这就是一个URL,其实通俗来讲,它就是我们所说的网址。
一个完整的URL包括:

目录    解释
协议名    http 或者 https
登录认证信息    可选,一般不可见
服务器地址    www.google.com
服务器端口号    http是80 https是 443(比http更加保密的协议) ssh是 22
带层次的文件路径    这里没显示出来,一般是一个相对路径比如:/dir/index.html
查询字符串    这里显示的是search?q = URL(?之前是访问的资源,后面是传输的参数,=各个参数之间用 & 分隔)
片段标识符    …
HTTP协议格式
画一张图以便理解和记忆:

HTTP请求格式


格式    内容
首行    方法+URL+版本号(版本号现在浏览器一般都支持 HTTP/1.1)
Header(头部)    请求的属性,冒号分割的键值对,每组属性之间使用 \n 分隔,遇到空行表示Header部分结束
Body    空行后面都是body。Body允许为空字符串。如果Body存在,则在Header中有一个Content-Length来标记Body长度
HTTP请求方法
方法    说明    支持的HTTP协议版本
GET    获取资源 (通过URL传参,一般数量是有限的)    1.0、1.1
POST    获取传输实体的主体(通过正文传参)    1.0、1.1
PUT    传输文件    1.0、1.1
HEAD    回去报文首部    1.0、1.1
DELETE    删除文件    1.0、1.1
OPTIONS    询问支持的方法    1.1
TRACE    追踪路径    1.1
CONNECT    邀请用隧道协议来连接代理    1.1
LINK    建立和资源之间的关系    1.0
UNLNE    断开连接关系    1.0
其中我们最常用的就是 GET 和POST请求。

HTTP响应

看起来HTTP响应格式跟请求很相似:

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

类型    类别    解释
1xx    Informational(信息状态码)    接受的请求正在处理
2xx    Success(成功状态码)    请求正常处理完毕
3xx    Redirection(重定向状态码)    需要进行附加操作已完成请求
4xx    Client Error(客户端错误状态码)    服务器无法处理请求
5xx    Server Error(服务器错误状态码)    服务器处理请求错误
常见状态码:
200(OK)、404(Not Found)、403(Forbidden)、302(重定向)、504(Bad Gateway)

HTTP常见Header:

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

#include <iostream>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <cstdio>
using namespace  std;

int main(int argc,char* argv[])
{
  if(argc != 3)
  {
    cerr << argv[0] << " ip port"<< endl;
    exit(0);
  }
  int fd = socket(AF_INET,SOCK_STREAM,0);
  if(fd < 0)
  {
    cerr<< "socket error" << endl;
    exit(1);
  }
  struct sockaddr_in addr;
  addr.sin_family = AF_INET;
  addr.sin_port = htons(atoi(argv[2]));
  addr.sin_addr.s_addr = inet_addr(argv[1]);

  int ret = bind(fd,(struct sockaddr*)&addr,sizeof(addr));
  if(ret < 0)
  {
    cerr<< "bind error"<< endl;
    exit(2);
  }
  ret = listen(fd,5);
  if(ret < 0)
  {
    cerr<< "listen error " << endl;
    exit(3);
  }
  while(1)
  {
    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;
    }
    cout<< "[Request] "<< input_buf << endl;
    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;
}

说完状态码,我们再来谈谈端口号:

端口号: 就是 用来标识一台主机上进行通信的不同的应用程序

在TCP/IP中,用一个五元组来标识一个通信:

五元组
五元组: 即源IP、源端口号、目的IP、目的端口号、协议号

查看指令:nenstat -n

端口号的划分范围:

0 - 1023:表示知名端口号,常见的HTTP、HTTPS、SSH、FTP都属于知名端口号,都是固定的。
1024 - 65535 :操作系统动态分配的端口号。客户端程序的端口号就是由操作系统动态分配出来的。
知名端口号: cat /etc/services 可以查看知名端口号

ssh服务器, 使用22端口
ftp服务器, 使用21端口
telnet服务器, 使用23端口
http服务器, 使用80端口
https服务器, 使用443
那么问题来了(面试题):

一个进程是否可以bind多个端口号?
答:可以,一个进程可以有多个socket,每个socket可以bind一个端口号。
一个端口号是否可以被多个进程bind?
答:不可以。前面我们说过端口号是用来标识一台主机上不同的应用程序,一个应用程序就是一个进程,如果可以的话,那么这个端口号标识的是哪一个进程呢。
但是, 非要这样做也不是没有办法,可以    在一个进程bind一个端口号之后 fork出一个子进程,该子进程也可以拥有此 端口号。
最后介绍两个查看网络状态的指令:

netstat 用来产看网络状态的重要工具
语法: nestat 【选项】
功能: 产看网络状态
常用选项:

拒绝显示别名,能显示数字的全部转化成数字
l 仅列出有在 Listen (监听) 的服務状态
p 显示建立相关链接的程序名
t (tcp)仅显示tcp相关选项
u (udp)仅显示udp相关选项
a (all)显示所有选项,默认不显示LISTEN相关
查看TCP: netstat -alpt
查看UDP: netstat -alpu
pidof 查看服务器进程id
功能:通过进程名,查看进程id
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值