网络协议随记(上)

一、基本概念

1、客户端VS服务器

在这里插入图片描述

  • JVM是java machine environment的简称,即java虚拟机
  • Tomcat是服务器最常用的软件,绑定一个端口即可使用,通过启动服务器软件来执行客户端提交的代码

2、访问服务器的项目

访问http://ip地址:端口/项目地址,例如:

访问http:192.168.12.32:8080/qq/login?user=root&passwd=123

ip地址为127.0.0.1或者localhost即本地ip地址

3、网络参考模型

  • OSI参考模型(七层)

在这里插入图片描述

  • TCP/IP模型(四层)

在这里插入图片描述

网络接口层:物理层、数据链路层

4、搭建一个简易的web服务器

4.1创建一个java工程

在intellJ idea创建一个java工程,这里创建了一个01test工程示例:

在这里插入图片描述

4.2添加web框架支持

我这里为了展示如何添加,新建了一个工程02test:

在这里插入图片描述

在这里插入图片描述

点击确定即可。

4.3给web配置tomcat服务器

这里给web配置的是最常用的tomcat服务器,tomcat服务器是开源的轻量级Web应用服务器,操作如下:

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

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

​ 选择第一项工件,然后选择当前的项目,再滑到下面,修改应用程序上下文,此处为修改url的访问地址,修改后可以此名字来访问当前项目,这么做是为了以后访问的方便,不改亦可以。例如修改为/02test(一定不要漏了/),访问url变为http://127.0.0.1:8080/02test,否则默认为http://127.0.0.1:8080/02Test_war_exploded。然后,点击确定。

在这里插入图片描述

在这里插入图片描述

接着,点击运行或者调试tomcat服务器,开始部署服务器:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

服务器输出框显示部署成功,随之浏览器弹出新窗口,显示 E N D END END,即完成部署工作。

4.4添加tomcat库

因为web要依赖服务器库,这里要添加tomcat库:

在这里插入图片描述

点击,选择项目结构

在这里插入图片描述

添加库,选择电脑上安装的tomcat库,点击添加,最后确定,会发现外部库中多了tomcat库:

在这里插入图片描述

4.5添加html文件

新建html文件夹,这里做个简单的登录页面,添加的html源代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录窗口</title>
</head>
<body>
<!--创建登录界面-->
<form action="/02test" method="post">
    <div>用户名<input name="username"></div>
    <div>密码  <input name="password"></div>
    <button type="submit">登录</button>
</form>
</body>
</html>

这里可以尝试在浏览器访问http://localhost:8080/02test/html/login.html,得到登录页面:

在这里插入图片描述

4.6添加java文件

为了处理客户端传送过来的数据,在这里简单写个服务器处理脚本。由于读者资源有限,本电脑兼任客户端、服务器两者。在src文件夹下添加java类,类名命名为com.syy.servlet.LoginServlet,源代码如下:

package com.syy.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

/**
 * 处理登录请求
 */
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1、获取客户端发送的数据(请求参数)
        String username = req.getParameter("username");
        String password = req.getParameter("password");

        System.out.println(username + "  " + password);

        //2、判断
        if ("syy".equals(username) && "123".equals(password)){
            //登录成功
            resp.getWriter().write("Login successful!");
        }
        else {
            resp.getWriter().write("Login failure!");
        }
    }
}

在这里插入图片描述

4.7修改html文件

因为想要给服务器返回客户端的提交信息,故要在原来的login.html作修改:

  • 查找web服务器的服务器接口名字,这里是/login

在这里插入图片描述

  • 在login.html文件中加入web服务器的服务器接口名字

4.8验证

点击调试,选择重新部署,在浏览器的登录页面输入用户名、密码(这里我输入的是syy、123),可看到登录成功的界面,并在服务器输出框返回了用户名、密码:

在这里插入图片描述

在这里插入图片描述

二、集线器-网桥-交换机

1、设备之间的连线

  • 同种设备之间用交叉线,不同种设备用直通线

2、数据发送的顺序

  • 先发ARP数据包进行广播
  • 再发ICMP数据包进行控制,也可以说是差错通知与信息查询

3、网桥

  • 在同一个网段里传输数据,工作在数据链路层,无mac地址
  • 只有两个端口
  • 可以通过自学习得知两个端口侧所有设备的MAC地址,即建立了一张MAC地址表,从而可以隔绝冲突域

4、交换机

  • 相当于接口更多的网桥,二级交换机工作在数据链路层,三层交换机工作在网络层,有ip地址和mac地址
  • 是局域网的最终方案,即在同个网段工作,所以不能跨网段(除了三层交换机)

三、MAC地址_IP地址__子网掩码

1、MAC地址操作

在这里插入图片描述

2、查看所有网络连接

PS C:\Users\Y> ipconfig /all

3、arp相关命令

在这里插入图片描述

4、IP地址的分类

  • A类:0开头,网络ID即0-127,但是可以分配给主机的只能是1-126,因为0不能用,127作为保留网段
  • B类:10开头,即128-191
  • C类:110开头,即192-223,平常我们用的192.168.1.10属于C类
  • D类:1110开头,多播地址
  • E类:1111开头,保留为今后使用
  • 127.0.0.1是本地环回地址,代表本地地址

5、网段与网关

  • 网段是主机位为0,比如192.168.1.0,一般称为网络号
  • 网关一般是主机位为1,比如192.168.1.1,一般设为路由器的端口ip地址

6、不同网段之间的Ping

发送者会用自己的子网掩码来计算对方的网段,跟自己的网段比较,若在同一网段则可ping通,否则超时。

四、超网_静态路由

1、超网概念

超网跟子网反过来,它是将多个连续的网段 合并成一个更大的网段。

其实就是将子网掩码往左移,增加主机数

2、默认路由

默认路由是一种特殊的静态路由,指的是当 路由表中与包的目的地址之间没有匹配的表项时,路由器能够做出选择。如果没有默认路由,那么目的地址在路由表中没有匹配表项的包将被丢弃。

在这里插入图片描述

3、默认路由与具体路由的使用

  • 当有多种路由要传输到同一个端口时,则用默认路由
  • 当有确定且为下一跳的路由,则用具体的路由

五、局域网_NAT

1、网络分类

  • LAN(local area network):局域网
  • MAN(metropolitan area network:域域网
  • WAN(wide。。):广域网

2、私网网段

  • A类:10.0.0.0/8,1个A类网络网段
  • B类:172.16.0.0-172.31.0.0/16 ,16个B类网络网段
  • C类:192.168.0.0-192.168.255.0/24,256个C类网络网段

3、NAT

  • NAT转换出的公网ip是离服务器最近的路由ip
  • 采用PAT端口转换机制

六、物理层_数据链路层

1、各层对应协议及传输数据格式

在这里插入图片描述

2、数据链路层

2.1三个基本问题

  • 封装成帧
  • 透明传输
  • 差错检验

2.2封装成帧

在这里插入图片描述

注意点:在进行传输时,各个传输端点之间(例如PC与交换机、PC与路由器、路由器与路由器等),会将上个链路传输下来的PDU去掉头部尾部的协议信息,再加上自己的协议信息,例如以太网协议(集线器、交换机使用的协议)、PPP协议(路由器的点到点协议),再传输给下一个链路。

2.3差错检验

在这里插入图片描述

当传输协议改变时,即头部信息改变,FCS也会改变。

以太网帧传输的字节至少要64字节,以太网帧现在使用最多的格式为Ethernet V2标准。

2.4Ethernet V2帧的格式

在这里插入图片描述

2.5Ethernet V2标准

在这里插入图片描述

2.6PPP协议

在这里插入图片描述

2.7网卡

在这里插入图片描述

wireshark抓到的帧是经过了校验差错的帧(FCS被网卡过滤掉了),故没有FCS。

七、网络层

1、ip包数据格式

在这里插入图片描述

2、ping的几个用法

在这里插入图片描述

八、传输层

1、TCP、UDP比较

在这里插入图片描述

2、UDP

2.1数据格式

在这里插入图片描述

2.2端口

在这里插入图片描述

3、TCP

3.1标志位(flags)

在这里插入图片描述

3.2建立连接–3次握手

在这里插入图片描述

seq为序号,ack为希望对方发送的序列号。

3.2.1前两次握手的特点

在这里插入图片描述

3.2.2为什么要进行三次握手

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

3.3释放连接–四次挥手

在这里插入图片描述

3.3.1状态解读

在这里插入图片描述

在这里插入图片描述

注意:由于FIN-WAIT、LAST-ACK状态非常短暂,在cmd用netstat -n查看所有端口状态时,只显示ESTABLISHED、TIME-WAIT、CLOSE-WAIT、CLOSED这四个状态。通常,可以用TIME-WAIT表示客户端,CLOSE-WAIT表示服务器。

3.3.2释放细节

在这里插入图片描述

3.3.3为什么要进行四次挥手

在这里插入图片描述

3.3.4抓包

在这里插入图片描述

在这里简单写了一个TCP服务器与客户端通信的程序:

客户端代码:

package com.mj;

import java.awt.FlowLayout;
import java.awt.Font;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;

@SuppressWarnings("serial")
public class TCPClient2 extends JFrame {
	
	public TCPClient2() {
		setTitle("客户端2");
		setBounds(300, 300, 600, 400);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setLayout(new FlowLayout(FlowLayout.LEFT, 20, 20));
		
		// 字体
		Font font = new Font("微软雅黑", Font.PLAIN, 18);
		
		JLabel label = new JLabel();
		label.setFont(font);
		add(label);
		
		JTextField tf = new JTextField(10);
		tf.setFont(font);
		add(tf);
		
		JButton saveBtn = new JButton("发送");
		saveBtn.setFont(font);
		saveBtn.addActionListener((evt) -> {
			try (
				Socket socket = new Socket("127.0.0.1", Constants.PORT);
				OutputStream os = socket.getOutputStream();
				InputStream is = socket.getInputStream();
				ByteArrayOutputStream baos = new ByteArrayOutputStream();
			) {
				// 写数据到服务器
				os.write(tf.getText().getBytes("UTF-8"));
				// 关闭输出(表明写给服务器的内容都写完了)
				socket.shutdownOutput();
				
				// 读取服务器发送的数据
				byte[] buffer = new byte[8192];
				int len;
				while ((len = is.read(buffer)) != -1) {
					baos.write(buffer, 0, len);
				}
				byte[] bytes = baos.toByteArray();
				label.setText(new String(bytes, "UTF-8"));
			} catch (Exception e) {
				e.printStackTrace();
			}
		});
		add(saveBtn);
		
	}

	public static void main(String[] args) throws Exception, IOException {
		new TCPClient2().setVisible(true);
	}
	
}

服务器代码:

package com.mj;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class TCPServer2 {
	public static void main(String[] args) throws Exception {
		try (ServerSocket server = new ServerSocket(Constants.PORT)) {
			System.out.println("服务器2----开始监听");
			while (true) {
				Socket client = server.accept();
				new Thread(() -> {
					try {
						doClient(client);
						client.close();
					} catch (Exception e) {
						e.printStackTrace();
					}
				}).start();
			}
		}
	}
	
	static void doClient(Socket client) throws Exception {
		try (
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			InputStream is = client.getInputStream();
			OutputStream os = client.getOutputStream();
		) {
			// 读取客户端的数据
			byte[] buffer = new byte[8192];
			int len;
			while ((len = is.read(buffer)) != -1) {
				baos.write(buffer, 0, len);
			}
			byte[] bytes = baos.toByteArray();
			String content = new String(bytes, "UTF-8");
			String ip = client.getInetAddress().getHostAddress();
			System.out.format("服务器2接收到[%s]的数据:%s%n", ip, content);
			
			// 写数据给客户端
			os.write(doString(content).getBytes("UTF-8"));
		}
	}
	
	static String doString(String str) {
		str = str.replace("你", "朕");
		str = str.replace("吗", "");
		str = str.replace("么", "");
		str = str.replace("?", "!");
		return str.replace("?", "!");
	}
	
	static void test() {
//		ServerSocket serverSocket = new ServerSocket(8888);
//		Socket socket = serverSocket.accept();
//		
//		ByteArrayOutputStream baos = new ByteArrayOutputStream();
//        InputStream is = socket.getInputStream();	
//		byte[] buffer = new byte[8192];
//		int len;
//		while ((len = is.read(buffer)) != -1) {
//			baos.write(buffer, 0, len);
//		}
//		byte[] bytes = baos.toByteArray();
//		
//		String string = new String(bytes, "UTF-8");
//		
//		System.out.format("服务器接收到[%s]的数据:%s%n", socket.getInetAddress(), string);
//        
//		is.close();
//        baos.close();
//		socket.close();
//		serverSocket.close();
	}
}

端口设置代码:

package com.mj;

public class Constants {
    public static final int PORT = 8888;
}

用wireshark抓了一下四次挥手的包:

2104	373.700684	127.0.0.1	127.0.0.1	TCP	44	1184 → 8888 [FIN, ACK] Seq=4 Ack=1 Win=2619648 Len=0
2105	373.700695	127.0.0.1	127.0.0.1	TCP	44	8888 → 1184 [ACK] Seq=1 Ack=5 Win=2619648 Len=0
2106	373.709662	127.0.0.1	127.0.0.1	TCP	47	8888 → 1184 [PSH, ACK] Seq=1 Ack=5 Win=2619648 Len=3
2107	373.709690	127.0.0.1	127.0.0.1	TCP	44	1184 → 8888 [ACK] Seq=5 Ack=4 Win=2619648 Len=0
2108	373.710083	127.0.0.1	127.0.0.1	TCP	44	8888 → 1184 [FIN, ACK] Seq=4 Ack=5 Win=2619648 Len=0
2109	373.710122	127.0.0.1	127.0.0.1	TCP	44	1184 → 8888 [ACK] Seq=5 Ack=5 Win=2619648 Len=0

第1、2、5、6行是四次挥手的包,第3、4行是服务器给客户端发送的数据包。

当server收到client的FIN时,如果server没有数据要发给client,则server会将第2、3次挥手合并为一次挥手。

7	1.357038	172.26.236.210	180.163.151.162	TCP	54	29060 → 443 [FIN, ACK] Seq=1 Ack=74 Win=510 Len=0
8	1.402669	180.163.151.162	172.26.236.210	TCP	60	443 → 29060 [FIN, ACK] Seq=74 Ack=2 Win=322 Len=0
9	1.402743	172.26.236.210	180.163.151.162	TCP	54	29060 → 443 [ACK] Seq=2 Ack=75 Win=510 Len=0

4、长链接与短链接

长链接:服务器与客户端一旦连接之后,中间需要保持连接来持续发送数据。长链接一般用于TCP保活,多用于操作频繁,点对点的通讯,而且连接数不能太多情况。

短链接:跟长链接相反,服务器与客户端连接之后,一旦完成一次读写传递操作,则断开连接。短链接一般用于web网站的http服务器,因为web网站会有成千上万的客户端进行连接,用短链接可以节省资源。当客户端数量庞大且无需频繁操作时,用短链接合适。

包。

当server收到client的FIN时,如果server没有数据要发给client,则server会将第2、3次挥手合并为一次挥手。

7	1.357038	172.26.236.210	180.163.151.162	TCP	54	29060 → 443 [FIN, ACK] Seq=1 Ack=74 Win=510 Len=0
8	1.402669	180.163.151.162	172.26.236.210	TCP	60	443 → 29060 [FIN, ACK] Seq=74 Ack=2 Win=322 Len=0
9	1.402743	172.26.236.210	180.163.151.162	TCP	54	29060 → 443 [ACK] Seq=2 Ack=75 Win=510 Len=0

4、长链接与短链接

长链接:服务器与客户端一旦连接之后,中间需要保持连接来持续发送数据。长链接一般用于TCP保活,多用于操作频繁,点对点的通讯,而且连接数不能太多情况。

短链接:跟长链接相反,服务器与客户端连接之后,一旦完成一次读写传递操作,则断开连接。短链接一般用于web网站的http服务器,因为web网站会有成千上万的客户端进行连接,用短链接可以节省资源。当客户端数量庞大且无需频繁操作时,用短链接合适。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值