Java网络编程,使用UDP实现TCP(一), 基本实现三次握手

简介:

首先我们需要知道TCP传输和UDP传输的区别,UDP相当于只管发送不管对方是否接收到了,而TCP相当于打电话,需要进行3次握手,4次挥手,所以我们就需要在应用层上做一些功能添加,如:

  • 增加ack机制

  • 增加seq机制

  • 增加超时重传机制

  • 增加MTU机制

  • 增加数据校验机制

即可实现简单的用UDP实现TCP功能。

part1:了解Java网络编程如何实现UDP和TCP

UDP:

UDP客户端发送数据:

  • 创建UDP套接字:使用DatagramSocket类创建一个UDP套接字,用于发送和接收UDP数据报。可以指定端口号或让系统自动分配一个可用端口。

  • 准备发送的数据,转成字节数组。

  • 构造UDP数据报:创建一个DatagramPacket对象,用于封装要发送的数据和目标主机的信息。需要提供要发送的数据的字节数组、数据的长度、目标主机的IP地址和端口号。

  • 发送数据报:使用UDP套接字的send()方法将封装好的数据报发送给目标主机。该方法接受一个DatagramPacket对象作为参数。

  • 关闭套接字:使用UDP套接字的close()方法关闭套接字,释放相关的资源。

import java.io.IOException;
import java.net.*;public class UDPClient {public static void main(String[] args) throws IOException {System.out.println("发送启动中。。。");//1. 使用 DatagramSocket(8888)DatagramSocket datagramSocket = new DatagramSocket(8888);//2. 准备数据,一定要转成字节数组String data = "hello java";//创建数据,并把数据打包byte[] datas = "hello java".getBytes();DatagramPacket datagramPacket = new DatagramPacket(datas, 0,datas.length, new InetSocketAddress("localhost",9999));//调用对象发送数据datagramSocket.send(datagramPacket);//关闭流datagramSocket.close();}
}

 UDP服务端接收数据:

  • 创建UDP套接字:使用DatagramSocket类创建一个UDP套接字,用于发送和接收UDP数据报。可以指定端口号或让系统自动分配一个可用端口。

  • 创建一个字节数组用于接收发送的数据。

  • 构造UDP数据报:创建一个DatagramPacket对象,用于封装要发送的数据和目标主机的信息。需要提供要发送的数据的字节数组、数据的长度、目标主机的IP地址和端口号。

  • 发送数据报:使用UDP套接字的receive()方法将封装好的数据报发送给目标主机。该方法接受一个DatagramPacket对象作为参数。

  • 关闭套接字:使用UDP套接字的close()方法关闭套接字,释放相关的资源。

package TCP_UDP_Practice.UDPrecieve;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;public class UDPClient {public static void main(String[] args) throws IOException {System.out.println("接收方接收中。。。");DatagramSocket datagramSocket = new DatagramSocket(9999);byte[] container = new byte[1024 * 60];DatagramPacket packet = new DatagramPacket(container, 0, container.length);datagramSocket.receive(packet);System.out.println(new String(packet.getData(), 0, packet.getLength()));datagramSocket.close();}
}

TCP:

TCP客户端发送数据:

  • 创建TCP客户端套接字:在服务器接受到客户端的连接请求后,将创建一个新的TCP套接字,用于和客户端进行通信。服务器套接字和客户端套接字之间建立了一条连接。

  • 数据传输:使用客户端套接字和服务器套接字进行数据传输。可以使用输出流来写入数据。服务器套接字和客户端套接字之间可以进行双向的数据传输。

  • 关闭连接:当数据传输完成或需要关闭连接时,可以调用套接字的close()方法关闭连接。关闭连接后,服务器套接字将继续监听新的连接请求。

package TCP_UDP_Practice.TCPsendMsg;import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;public class ClientDemo {public static void main(String[] args) throws IOException {Socket socket = new Socket("127.0.0.1", 10005);//创建输入流对象,写入数据OutputStream outputStream = socket.getOutputStream();outputStream.write("hello tcp".getBytes());//关闭流socket.close();}
}

TCP服务端接收数据:

  • 创建TCP服务器套接字:使用ServerSocket类创建一个TCP服务器套接字,用于监听客户端的连接请求。需要指定服务器的端口号。
  • 数据传输:使用客户端套接字和服务器套接字进行数据传输。可以使用输入流来读取数据。服务器套接字和客户端套接字之间可以进行双向的数据传输。

  • 关闭连接:当数据传输完成或需要关闭连接时,可以调用套接字的close()方法关闭连接。关闭连接后,服务器套接字将继续监听新的连接请求。

package TCP_UDP_Practice.TCPrecieve;import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class ServerDemo {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(10005);Socket accept = serverSocket.accept();//获取输入流InputStream inputStream = accept.getInputStream();byte[] bytes = new byte[1024];int read = inputStream.read(bytes);String s = new String(bytes, 0, read);System.out.println("数据是:" + s);//关闭流serverSocket.close();}
}

Part2:用UDP如何实现TCP的三次握手?

参考《TCP/IP详解》卷一的424页,我们可以得知三次握手须传输的主要数据有SYN, Seq和ACK,接下来我将详细说说三次握手这些数据有何变化,如何获取。

第一次握手:

  • 客户端会发送一个SYN 报文段(即一个在TCP头部位置SYN位置的TCP/IP数据包),并指明自己想要连接到的端口号和它的客户端初始序列号ISN。客户端发送的这个SYN报文段称为段1。
  •  那么问题来了:SYN,ISN到底如何获取,如何用Java程序写出来呢?
    • SYN:(Synchronize)是TCP(传输控制协议)中的一个标志位,用于建立连接的过程中进行同步。在TCP三次握手的过程中,SYN用于表示发起连接请求的一方(通常是客户端)希望建立连接。SYN标志位的值为1,表示发起连接请求或确认连接请求。
    • Seq:(Sequence Number)是用于标识数据字节顺序的字段。每个TCP报文段都包含一个Seq字段,用于指示报文段中的数据字节在整个数据流中的位置。

      • Seq字段的值表示报文段中的第一个数据字节的序列号。每个字节都有一个唯一的序列号,序列号从一个初始值开始,并随着每个传输的字节递增。

      • 在TCP连接建立后,双方会通过ISN(Initial Sequence Number)来初始化序列号。ISN是一个随机选择的32位无符号整数,用作初始的序列号。之后,发送方在发送数据时,会为每个报文段分配一个递增的序列号。

      • 接收方在接收到报文段时,根据Seq字段的值来确定数据字节的顺序。如果接收方发现某个报文段的Seq值不连续或重复,它会通知发送方进行相应的处理,以确保数据的正确传输和重组。

      • Seq字段的作用是保证TCP数据的有序性和可靠性。通过正确的序列号,接收方可以按正确的顺序重组数据,并检测丢失或重复的数据。

      • 需要注意的是,Seq字段的范围是32位无符号整数,因此序列号会在达到最大值后重新从0开始循环。

    • ISN:(Initial Sequence Number)是TCP(传输控制协议)中用于初始化序列号的值。序列号用于标识TCP报文段中的数据字节顺序,以便接收方可以按正确的顺序重组数据。

      在TCP连接建立时,双方需要协商一个初始的序列号。

      • ISN是一个随机选择的32位无符号整数,通常由操作系统生成。ISN的选择是为了增加连接的安全性,防止恶意攻击者猜测序列号并插入伪造的数据。

      • ISN的选择是根据一些算法和系统状态进行的,具体的实现可能因操作系统而异。通常,ISN的选择会考虑到时间、IP地址、端口号等因素,以确保序列号的唯一性和随机性。在[RFC1948]中提出了一个较好的初始化序列号ISN随机生成算法。ISN = M + F(localhost, localport, remotehost, remoteport). 

        注意:M是一个计时器,这个计时器每隔4毫秒加1。F是一个Hash算法,根据源IP、目的IP、源端口、目的端口生成一个随机数值。要保证hash算法不能被外部轻易推算得出,用MD5算法是一个比较好的选择。
      • 一旦双方在三次握手过程中成功建立连接,ISN就会被用作初始的序列号,并在后续的数据传输中递增。序列号的递增是为了确保数据的有序传输和重组。

      • 需要注意的是,ISN是每个TCP连接独立选择的,不同的连接会有不同的ISN。这样可以避免一个连接中的序列号被用于另一个连接,从而增加连接的安全性。

ISN初始化代码如下:

package TCP_handShake;import java.time.LocalDateTime;
import java.util.UUID;/*** 初始化Seq的值ISN* RFC1948中提出了一个较好的初始化序列号ISN随机生成算法:* ISN = M + F(localhost, localport, remotehost, remoteport).**/
public class initializeISN {private int ISN = generateISN() ;public int getISN() {return ISN;}private int generateISN(){// 获取当前时间String currentTime = String.valueOf(LocalDateTime.now().getSecond());// 生成UUIDUUID uuid = UUID.randomUUID();// 将时间和UUID结合生成ISNString isnString = currentTime + uuid.toString();int isn = isnString.hashCode();return isn;}
}

在我的代码中,由于我的目的是简单的实现,所以并未采用 [RFC1948]提到的算法,而是使用当前时间的秒数(通过LocalDateTime类得到)和UUID进行字符串拼接,实现了唯一性。(由于没有做到后面的内容,如后续如发现有问题,会进行更改

SYN和Seq初始化代码如下

package TCP_handShake;/*** 标志位 connectionMarks*/
public class ConnectionMarks extends initializeISN{//每次建立新连接,将SYN初始化为1private int SYN;//获取ISNprivate int Seq;public ConnectionMarks() {this.SYN = 1;this.Seq = getISN();}public int getSeq() {return Seq;}//setter of SYNpublic Integer getSYN() {return SYN;}
}

第一次握手客户端发送数据:

 System.out.println("第一次握手:");System.out.println("正在发送SYN和Seq......");//1. 使用 DatagramSocket(8888)DatagramSocket datagramSocket = new DatagramSocket(8888);ConnectionMarks connectionMarks = new ConnectionMarks();String SYN = String.valueOf(connectionMarks.getSYN());//getSeq() 方法值等同于 getISN(),获取ISN(c)int ISN1 = connectionMarks.getSeq();String Seq = String.valueOf(ISN1);//2. 准备数据,一定要转成字节数组String data = SYN + " " + Seq;//创建数据,并把数据打包byte[] datas = data.getBytes();DatagramPacket datagramPacket = new DatagramPacket(datas, 0,datas.length, new InetSocketAddress("localhost",9999));//调用对象发送数据datagramSocket.send(datagramPacket);//关闭流datagramSocket.close();

第一次握手服务端接收数据:

  System.out.println("接收数据:...");//创建接收端对象DatagramSocket datagramSocket = new DatagramSocket(9999);//创建数据包,用于接收数据byte[] bytes = new byte[1024];DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);datagramSocket.receive(datagramPacket);String s = new String(datagramPacket.getData(), 0, datagramPacket.getLength());//解析数据包并且输出显示System.out.println("数据为: " + s);//关闭流datagramSocket.close();

第二次握手:

  1. 服务端收到客户端的SYN包(SYN=j)后,需要回复一个SYN+ACK的包给客户端。
  2. 这个SYN+ACK的包里,ACK的值为j+1,表示"我已经收到你的SYN了"。
  3. 同时,服务端也会发送自己的SYN包,序列号为ISN(s),这个序列号是服务端自己生成的。

服务端在第二次握手中发送的包,其SYN和ACK标志位都被设置为1(SYN+ACK),序列号(Seq)为服务端自己生成的初始序列号(ISN(s)),确认号(ACK)为客户端的初始序列号加1(ISN(c)+1)。

注意:此处ACK为一个flag标志位,只是说明得到了ACK

在connectionMark类补充ACKMark的初始化

package TCP_handShake;/*** 标志位 connectionMarks*/
public class ConnectionMarks extends initializeISN{//每次建立新连接,将SYN初始化为1private int SYN;//随机private int Seq;private  int ACKMark;public int getACKMark() {return ACKMark;}public void setACKMark(int ACKMark) {this.ACKMark = ACKMark;}public ConnectionMarks() {this.SYN = 1;this.Seq = getISN();this.ACKMark = 0;}public int getSeq() {return Seq;}//setter of SYNpublic Integer getSYN() {return SYN;}
}

第二次握手服务端发送数据:

System.out.println("====================");System.out.println("第二次握手:");System.out.println("正在发送SYN, Seq 和 ACK......");ConnectionMarks connectionMarks = new ConnectionMarks();//第二次握手,返回ACK = ISN + 1;//生成自己的ISN(s)String Seq2 = String.valueOf(connectionMarks.getSeq());//ACK2中的ISN为第一次传过来的ISN(c)+1String ACK2 = String.valueOf(ISN1+ 1);//将ack标志位设为1connectionMarks.setACKMark(1);String SYN2 = connectionMarks.getSYN() + "/" + connectionMarks.getACKMark();//2. 准备数据,一定要转成字节数组String data2 = SYN2 + " " + Seq2 + " " + ACK2;//创建数据,并把数据打包byte[] datas2 = data2.getBytes();DatagramPacket datagramPacket2 = new DatagramPacket(datas2, 0,datas2.length, new InetSocketAddress("localhost",8888));//调用对象发送数据datagramSocket.send(datagramPacket2);

第二次握手客户端接收数据:

System.out.println("====================");System.out.println("接收数据:...");//创建数据包,用于接收数据/*** 在第二次握手中,客户端主要会检查两个方面的内容:* 检查ACK标志位:客户端需要确认服务端发送的确认信息(SYN-ACK)中的ACK标志位是否已设置。ACK标志位表示服务端确认收到了客户端的握手请求。* 检查确认号(ACK):客户端需要检查服务端发送的确认信息中的确认号(ACK)是否正确。确认号应该是服务端发送的初始序列号加1,用于告知服务端它已经正确接收到服务端的数据。*/byte[] bytes = new byte[1024];DatagramPacket datagramPacket2 = new DatagramPacket(bytes, bytes.length);datagramSocket.receive(datagramPacket2);String s = new String(datagramPacket2.getData(), 0, datagramPacket2.getLength());//拆分字符串获取其中的SYN,Seq和ACKString[] strArr = s.split(" ");String[] flag = strArr[0].split("/");//System.out.println(strArr[0]);//检验接收信息是否是满足需求的if (!(Integer.parseInt(flag[1]) != 0&& Integer.parseInt(flag[0]) == 1&& Integer.parseInt(strArr[2]) == ISN1 + 1)){//TODO 异常提醒,非本次连接,如何处理throw new RuntimeException("wrong connection");}System.out.println("通过校验");//解析数据包并且输出显示System.out.println("数据为: " + s);

注意:第一次握手服务端不需要进行校验,但是第二次握手用户端就需要进行校验,ACK标志位是否为1,ACK值是否为ISN(c)+1,SYN值是否为1。

第三次握手

第三次握手,客户端会发送以下三个数据:

  1. ACK标志位应该为1,表示确认收到第二次握手客户端发来的消息。
  2. Seq,值和第二次握手服务端传来的ACK相同
  3. ACK值,为第二次握手服务端传来的ISN(s)+1

第三次握手客户端发送数据:

System.out.println("====================");//第三次握手System.out.println("第三次握手:");System.out.println("正在发送SYN, Seq 和 ACK......");connectionMarks.setACKMark(1);String ackMark = String.valueOf(connectionMarks.getACKMark());String Seq3 = strArr[2];String ACK3 = String.valueOf(Integer.parseInt(strArr[1]) + 1);//2. 准备数据,一定要转成字节数组String data3 = ackMark + " " + Seq3 + " " + ACK3;
//        System.out.println("+++++++++++++++++");
//        System.out.println(ACK3);//创建数据,并把数据打包byte[] datas3 = data3.getBytes();DatagramPacket datagramPacket3 = new DatagramPacket(datas3, 0,datas3.length, new InetSocketAddress("localhost",9999));//调用对象发送数据datagramSocket.send(datagramPacket3);

第三次握手服务端接收数据

 System.out.println("====================");System.out.println("接收数据:...");//创建数据包,用于接收数据byte[] bytes3 = new byte[1024];DatagramPacket datagramPacket3 = new DatagramPacket(bytes3, bytes3.length);datagramSocket.receive(datagramPacket3);String s3 = new String(datagramPacket3.getData(), 0, datagramPacket3.getLength());//解析数据包并且输出显示System.out.println("数据为: " + s3);//拆分字符串获取其中的SYN,Seq和ACKString[] strArr3 = s.split(" ");//System.out.println(strArr[0]);//检验接收信息是否是满足需求的if (Integer.parseInt(strArr3[0]) != 1){//TODO 异常提醒,非本次连接,如何处理throw new RuntimeException("wrong connection");}System.out.println("通过校验,完成三次握手");

初步总结:

至此完成了简单的三次握手,但是并没有实现超时重传机制,MTU输入缓冲。后续会进行完善和修改,全部代码会在我完成整个TCP通信流程后,开源到GitHub,由于作者能力有限可能有一些错误还烦请大家指出来,我会第一时间进行反思和修改,感谢。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/205624.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Bounding boxes augmentation for object detection

Different annotations formats Bounding boxes are rectangles that mark objects on an image. There are multiple formats of bounding boxes annotations. Each format uses its specific representation of bouning boxes coordinates 每种格式都使用其特定的边界框坐标…

案例060:基于微信小程序考试系统

文末获取源码 开发语言:Java 框架:SSM JDK版本:JDK1.8 数据库:mysql 5.7 开发软件:eclipse/myeclipse/idea Maven包:Maven3.5.4 小程序框架:uniapp 小程序开发软件:HBuilder X 小程序…

01-SDV软件定义汽车思考

前言: 随着汽车产业“新四化”(电动化、网联化、智能化、共享化)的加速推动,智能汽车已成为各国科技发展战略重点,在社会数字化转型的浪潮下逐渐形成跨领域协作、多技术融合的汽车产业新赛道。 软件定义汽车已成为行业趋势与共识&#xff…

class037 二叉树高频题目-下-不含树型dp【算法】

class037 二叉树高频题目-下-不含树型dp【算法】 code1 236. 二叉树的最近公共祖先 // 普通二叉树上寻找两个节点的最近公共祖先 // 测试链接 : https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/ package class037;// 普通二叉树上寻找两个节点的最近…

HashMap系列-resize

1.resize public class HashMap<K,V> extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable {final Node<K,V>[] resize() {Node<K,V>[] oldTab table;int oldCap (oldTab null) ? 0 : oldTab.length; //老的数组容量in…

RabbitMQ学习二

RabbitMQ学习二 发送者的可靠性生产者连接重试机制生产者确认机制开启生产者确认定义ReturnCallback定义confirmCallback MQ的可靠性交换机和队列持久化消息持久化LazyQueue控制台配置Lazy模式代码配置Lazy模式 消费者的可靠性失败重试机制失败处理策略业务幂等性唯一消息ID业务…

AI人工智能在电子商务领域的运用

电子商务领域和个性化新时代的 AI 随着整个社会追求便利性&#xff0c;并且逐渐从传统的实体零售模式转向网购模式&#xff0c;在线零售商必须改变与客户的互动方式。为每个客户提供个性化购物体验的理念一直都存在&#xff0c;但是现在我们正式进入了个性化新时代。这是一个包…

Docker网络原理及Cgroup硬件资源占用控制

docker的网络模式 获取容器的进程号 docker inspect -f {{.State.Pid}} 容器id/容器名 docker初始状态下有三种默认的网络模式 &#xff0c;bridg&#xff08;桥接&#xff09;&#xff0c;host&#xff08;主机&#xff09;&#xff0c;none&#xff08;无网络设置&#xff…

【flink番外篇】1、flink的23种常用算子介绍及详细示例(2)- keyby、reduce和Aggregations

Flink 系列文章 1、Flink 专栏等系列综合文章链接 文章目录 Flink 系列文章一、Flink的23种算子说明及示例6、KeyBy7、Reduce8、Aggregations 本文主要介绍Flink 的3种常用的operator&#xff08;keyby、reduce和Aggregations&#xff09;及以具体可运行示例进行说明. 如果需要…

【vtkWidgetRepresentation】第五期 vtkLineRepresentation

很高兴在雪易的CSDN遇见你 内容同步更新在公众号“VTK忠粉” 【vtkWidgetRepresentation】第五期 一条直线的交互 前言 本文分享vtkLineRepresentation&#xff0c;希望对各位小伙伴有所帮助&#xff01; 感谢各位小伙伴的点赞关注&#xff0c;小易会继续努力分享&#xf…

Presto:基于内存的OLAP查询引擎

PrestoSQL查询引擎 1、Presto概述1.1、Presto背景1.2、什么是Presto1.3、Presto的特性2、Presto架构2.1、Presto的两类服务器2.2、Presto基本概念2.3、Presto数据模型3、Presto查询过程3.1、Presto执行原理3.2、Presto与Hive3.3、Presto与Impala3.4、PrestoDB与PrestoSQL4、Pre…

Libavutil详解:理论与实战

文章目录 前言一、Libavutil 简介二、AVLog 测试1、示例源码2、运行结果 三、AVDictionary 测试1、示例源码2、运行结果 四、ParseUtil 测试1、示例源码2、运行结果 前言 libavutil 是一个实用库&#xff0c;用于辅助多媒体编程&#xff0c;本文记录 libavutil 库学习及 demo 例…

智能优化算法应用:基于战争策略算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于战争策略算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于战争策略算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.战争策略算法4.实验参数设定5.算法结果6.参考…

对比两阶段提交,三阶段协议有哪些改进?

本文我们来讨论两阶段提交和三阶段提交协议的过程以及应用。 在分布式系统中&#xff0c;各个节点之间在物理上相互独立&#xff0c;通过网络进行沟通和协调。在关系型数据库中&#xff0c;由于存在事务机制&#xff0c;可以保证每个独立节点上的数据操作满足 ACID。但是&…

WMMSE方法的使用笔记

标题很帅 原论文的描述WMMSE的简单应用 无线蜂窝通信系统的预编码设计问题中&#xff0c;经常提到用WMMSE方法设计多用户和速率最大化的预编码&#xff0c;其中最为关键的一步是将原和速率最大化问题转化为均方误差最小化问题&#xff0c;从而将问题由非凸变为关于三个新变量的…

Zabbix“专家坐诊”第214期问答汇总

问题一 Q&#xff1a;Zabbix 6.4版本&#xff0c;如图&#xff0c;95th percentable这个值是否会存到zabbix的数据库里&#xff1f;如果存了是存到了哪里&#xff1f; A&#xff1a;这个值是不会保存到数据库里的&#xff0c;它会根据所选的时间段而变化。 问题二 Q&#xff1…

5分钟搞懂ECN

ECN是通过在IP和TCP头中携带拥塞信息&#xff0c;通知发送方网络拥塞状态&#xff0c;从而采取相应拥塞控制措施。原文: What is ECN(Explicit Congestion Notification)?[1] ECN是Explicit Congestion Notification的缩写&#xff0c;意思是显式拥塞通知算法&#xff0c;和慢…

黑苹果之主板篇

一、什么是主板 主板&#xff0c;又叫主机板&#xff08;mainboard&#xff09;、系统板&#xff08;systemboard&#xff09;、或母板&#xff08;motherboard&#xff09;&#xff0c;是计算机最基本的同时也是最重要的部件之一。主板一般为矩形电路板&#xff0c;上面安装了…

Zabbix自动发现机制

Zabbix的自动发现机制 Zabbix客户端主动的和服务端联系&#xff0c;将自己的地址和端口发送服务端&#xff0c;实现自动添加监控主机&#xff0c;客户端是主动的一方缺点自定义网段中主机数量太多&#xff0c;等级耗时会很久&#xff0c;而且这个自动发现机制不是很稳定 Zabb…

06 硬件知识入门(MOSS管)

1 简介 MOS管和三极管的驱动方式完全不一样&#xff0c;以NPN型三极管为例&#xff0c;base极以小电流打开三极管&#xff0c;此时三极管的集电极被打开&#xff0c;发射极的高电压会导入&#xff0c;此时电流&#xff1a;Ic IbIe &#xff1b;电压&#xff1a;Ue>Uc>Ub…