第四阶段C#通讯开发-4:网络通讯_网络协议
1_OSI
(1)OSI(Open System Interconnect),即开放式系统互联。 一般都叫OSI参考模型,是ISO(国际标准化组 织)组织在1985年研究的【网络互联模型】。该体系结构标准定义了【网络互连的七层框架】
2_网络七层架构
网络互连的七层框架,又称OSI开放系统互连参考模型。
分为七层:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。
遵守网络互连的两端在传递数据时,通过七层框架,层层按顺序传递的。
3_网络的互连
如网络有两端,一端称为服务器Server,一端称为客户端Client 【服务器】向【客户端】发送数据,【客户端】接收【服务器】传递的数据。 它们的过程如下:
【服务器】把数据通过七层框架一层一层向下传递: 从应用层->表示层->会话层->传输层->网络层->数据链路层->物理层
当【服务器】把数据传递到它的物理层后,由于【服务端】的物理层和【客户端】的物理层是通过物理设备连接的,可以直接通讯。【服务器】的物理层通过比特流的方式把数据传递到【客户端】的物理层。
【客户端】物理层接收到数据后,并一层一层向上传递: 从物理层->数据链路层->网络层->传输层->会话层->表示层->应用层
【客户端】把数据传递到它的应用层后,就可以在应用程序中使用了
4_每层主要功能及协议
应用层:负责应用程序的运行。常见的协议有【HTTP】、【HTTPS】、【Telnet】、【FTP】、【SMTP】、【DNS】 等
表示层:负责数据格式转换。常见的协议有【ASCII、UTF8, Unicode】, SSL/TLS、JPEG、GIF、DES、MPEG,LPP 等
会话层:负责建立和断开通信连接。常见的协议有ADSP、RPC、SQI等
传输层:负责可靠安全的进行数据传输。常见的协议有【TCP】、【UDP】、SPX 等
网络层:负责将数据传输到目标地址。常见的协议有【IP】、ICMP/ICMPv6、IGMP、IPX、ARP、RARP 等
数据链路层:负责物理层面上互连的节点之间的通信传输。常见的协议有HDLC、PPP、SLIP、ATM、IEEE802.2/.3、VLAN、STP,WIFI(IEEE 802.11)等
物理层:负责比特流(0、1序列)与电压高低、光的闪灭之间的互换。常见的协议UART、RS232/232C、RS422/423/449/485、RJ-45、V24、V35、FDDI、X.21、X.21bis等。
5_协议概述
(1)必须要掌握的协议有:IP(指网际互连协议,Internet Protocol的缩写)、TCP、UDP、HTTP/HTTPS、FTP、RS232/RS485、Modbus,S7NETPlus
了解的:
-
Telnet:telnet协议提供了一种通过终端远程登录到服务器的方式
-
SMTP:简单邮件传输协议,是一种用于发送电子邮件的网络协议
-
ARP:地址解析协议,是一种用于将网络层的地址转换为数据链路层地址的重要网络协议
-
RARP:逆地址解析协议,是一种网络协议,它允许局域网中的设备通过已知的物理地址(MAC地址)来请求分配IP地址
-
ASCII:美国信息交换标准代码(ASCII)的应用,主要用于字符编码和数据传输,广泛应用于计算机和通信设备之间的文本数据交换。
-
RS449/422/423、
-
RJ-45:RJ45是布线系统中信息插座(即通信引出端)连接器的一种,连接器由插头(接头、水晶头)和插座(模块)组成,插头有8个凹槽和8个触点
-
DNS:DNS 协议也是一种应用层的协议,DNS 使用客户-服务器模式运行在通信的端系统之间,在通信的端系统之间通过 UDP 运输层协议来传送 DNS 报文。
(2)RS232、RS422/423/449/485是串口通讯接口。串口通信协议有UART、RS232、RS422、RS423、RS449、RS485等。 RJ-45是网口通讯接口。RJ-45接口网卡是最为常见的一种网卡,也是应用最广的一种接口类型网卡。
对于我们学科TCP、UDP是重中之重。串口也要有一定的接触。
6_重要协议概述
IP(Internet Protocol)网络之间互连的协议,包括:IPv4/IPv6。寻址的协议。提醒:IP在网络层。 v version版本
TCP(Transfer Control Protocol)传输控制协议提供可靠的面向连接的服务,传输数据前须先建立连接,结束后释放。可靠的全双工信道。可靠、有序、无丢失、不重复。不易造成数据丢失,不易读脏数据。提醒:属于传输层,而非网络层。 类似“保安,保镖”,武功高。
UDP(User Datagram Protocol)用户数据报协议,发送数据前无需建立连接,不使用拥塞控制,不保证可靠交付,最大努力交付。容易造成数据丢失。易读取到脏数据。
FTP(File Transfer Protocol)文件传输协议,默认端口号为21。
HTTP(Hypertext Transfer Protocol)超文本传输协议,默认端口号为80。Hypertext超文本范围比较大,包含:音频,视频,图像,文本等
HTTPS(Hypertext Transfer Protocol Secure)安全的超文本传输协议,默认的端口号是443。是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性。HTTPS 在HTTP 的基础下加入SSL,HTTPS 的安全基础是 SSL。
RS-232标准接口(又称EIA RS-232)是常用的串行通信接口标准之一,它是由美国电子工业协会(Electronic Industry Association,EIA)联合贝尔系统公司、调制解调器厂家及计算机终端生产厂家于1970年共同制定,其全名是“数据终端设备( DTE)和数据通信设备(DCE)之间串行二进制数据交换接口技术标准”。
SSL:SL证书是数字证书的一种,类似于驾驶证、护照和营业执照的电子副本。因为配置在服务器上,也称为SSL服务器证书。https://baike.baidu.com/item/SSL%E8%AF%81%E4%B9%A6/5201468?fr=aladdin
7_注意
Socket 客户端 可以发送也可以接收 发送和接收都是使用 客户端实例
Socket 服务器 可以发送也可以接收 但是接收和发送并不是他"自身"做的,而是获取到连接他的某个客户端实例,让这个客户端实例去帮助服务器发送和接收数据
8_代码示例(暂时不全)
8.1_服务端
(1)实例化一个服务器:使用Socket这个类创建服务器实例
-
参数1指定Socket实例可以使用的寻址方案:AddressFamily,枚举类型,常用的就两个,AddressFamily.InterNetwork IP版本4的地址AddressFamily . InterNetworkV6, IP版本6的地址
-
参数2:指定Socket类的实例表示的套接字类型,SocketType枚举类型,此示例以流的形式传递数据
-
参数3以哪种协议进行通讯,ProtocolType枚举
(2)通过客户端实例client可以拿到几个重要信息:
属性 | 说明 |
---|---|
client.LocalEndPoint | 拿服务器身份(ip+端口号) |
client.RemoteEndPoint | 拿客户端身份 |
client.Available | 拿可供读取的数据字节数 |
client.Connected | 拿客户端连接状态 |
client.AddressFamily | 客户端使用哪种寻址方案和服务器通讯的 |
client.ProtocolType | 客户端使用哪种协议类型和服务器通讯的 |
client.SocketType | 客户端使用哪种Socket类型和服务器通讯的 |
client.ReceiveBufferSize | 客户端最大能接收的数据字节数 |
client.SendBufferSize | 客户端最大能发送的数据字节数: |
ReceiveTimeout | 客户端接收数据时的超时时间,超时值(以毫秒为单位)。 默认值为 0,指示超时期限无限大。 |
SendTimeout | 客户端发送数据时的超时时间,超时值(以毫秒为单位)。 默认值为 0,指示超时期限无限大。 |
//1.创建服务器实例
//使用Socket这个类创建服务器实例,在System.Net.Sockets;命名空间下,Net指的是Network 网络;
Socket server = null;
CancellationTokenSource cts1 = null;
CancellationTokenSource cts2 = null;
//在窗体加载的时候进行创建,并启动服务器
private void Form1_Load(object sender, EventArgs e)
{//1.实例化一个服务器//参数1指定Socket实例可以使用的寻址方案,//AddressFamily是一个枚举类型,常用的就两个,//AddressFamily.InterNetwork IP版本4的地址//AddressFamily.InterNetworkV6, IP版本6的地址//参数2:指定Socket类的实例表示的套接字类型,以流的形式传递数据SocketType枚举类型//参数3以哪种协议进行通讯,ProtocolType枚举server = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
//2.让服务器和某个ip地址和port端口号绑定在一起,确定服务器的身份,身份就是ip和端口号//EndPoint 终结点,抽象类,不能实例化//IPEndPoint:继承了EndPoint抽象类//IPAddress类:主要负责ip地址的创建//端口号:int类型,建议四位之前的端口不建议使用,操作系统中一些软件已经把四位的端口已经占用的差不多了,防止端口冲突//IPEndPoint.MaxPort最大值65535,//IPEndPoint.MinPort最小值 0;//http:80 https:443 ftp:21//sqlserver 1433 mysql;3306
//端口号int port = 12345;string ipstr = null;//172.16.0.45 本机的ip地址 局域网中的一个ip 此局域网中其他的客户端都能连接此ip,表示本机
//127.0.0.1 表示本机地址//locahost 本机域名也会转成127.0.0.1ip地址,使用127.0.0.1IP地址时,只能在本机中连接此服务器,局域网中其他的电脑不能连接此服务器
//ip地址//Dns域名,映射ip地址//Dns.GetHostName()获取当前加算计的主机名//Dns.GetHostEntry("主机名")把主机名映射成对应的ip地址
IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());//host.AddressList是一个数组,foreach(IPAddress ip in host.AddressList){if (ip.AddressFamily == AddressFamily.InterNetwork){ipstr= ip.ToString();}}IPAddress ipAddress= IPAddress.Parse(ipstr);IPEndPoint endPoint = new IPEndPoint(ipAddress, port);server.Bind(endPoint);
// server.Bind(new IPEndPoint(IPAddress.Parse("172.16.0.45"),9527));
//3.启动服务器(让服务器处于监听状态)server.Listen(100);//相当于seriaPort.Open();
//4.等待客户端发送过来的消息(接收客户端请求,)只要是服务器处于监听状态(服务器已经启动)立即可以接受服务端的请求//接受请求时,考虑如下问题://4.1 等待的过程中不能阻塞线程:说明要使用多线程,如Task//4.2 客户端会循环不断发送消息 说明要循环接受,如while//4.3 将来可能会有多个客户端 循环接受每一个客户端,每一个客户端循环每条消息,两层循环嵌套,两个分线程嵌套Console.WriteLine(server.LocalEndPoint);
//AccepDataSin();//一个客户端的情况AccepDataMtu();//多个客户端的情况
}
//客户端===》服务端 叫做请求
//服务端===》客户端 叫做响应
//接收客户端请求数据
private void AccepDataSin()
{
cts1 = new CancellationTokenSource();Task.Run(() =>{//先拿到客户端实例,通过这个实例就可以获取客户端的一些信息//比如,如上表Socket client = server.Accept();Console.WriteLine(client.LocalEndPoint);//ip+端口客户端的身份\
//循环接受客户端发送的数据while (!cts1.IsCancellationRequested){//server.Available:获取已经从网络中接受且可读取的数据字节数,就是客户端发送的总字节数byte[] buffer = new byte[client.Available];//Receive:将读取到的数据放到缓冲区中(buffer)//返回接收到的字节数int count =client.Receive(buffer);Invoke(new Action(() =>{richTextBox1.AppendText(Encoding.UTF8.GetString(buffer));}));
}},cts1.Token);
}
private void AccepDataMtu()
{//外层线程:处理多个客户端连接cts1 = new CancellationTokenSource();Task.Run(() =>{//第一层循环,循环每一个客户端while (!cts1.IsCancellationRequested){//Accept为新建的连接创建Socket实例Socket client = server.Accept();//在编程中,client.connectedO函数用于检查客户端是否成功连接到服务器。该函数返回一个布尔值,如果连接状态为真,则返回真;否则返回假。if (client.Connected){cts2= new CancellationTokenSource();//内层线程,处理某个客户端的多次请求Task.Run(() =>{//循环接收某个客户端的多次请求while (!cts2. IsCancellationRequested){// if (client.Available == 0) continue;try{byte[] buffer= new byte[client.Available];int count = client.Receive(buffer);Invoke(new Action(() =>{richTextBox1.AppendText(Encoding.UTF8.GetString(buffer));}));}catch(Exception ex){throw ex;}}}, cts2.Token).ContinueWith((t) =>{// //t上一个Task 上面的Task中抛出的异常 可以再此处捕获if (t.IsFaulted){//主线程foreach(var item in t.Exception.InnerExceptions){MessageBox.Show(item.Message);}}});}}}, cts1.Token);
}
8.2_客户端
//Socket 外壳,套接字,封装了Tcp,UDP中的各种协议,即可以创建服务器,也可以创建客户端
Socket client = null;
public Form1()
{InitializeComponent();
}
//连接
private async void button1_Click(object sender, EventArgs e)
{try{//1.实例化一格客户端,客户端的寻址方式,scoket的类型,协议类型,都要和服务器保持一致client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//2.客户端client和服务器server建立连接(三次握手)//远程终结点(远程终端),指的就是服务器,ip地址和port端口就是服务器的ip和端口IPEndPoint remoteEp = new IPEndPoint(IPAddress.Parse("192.168.40.1"), 12345);//连接//常见的异常:由于目标计算机积极拒绝,无法连接//排查错误:服务器没有启动,2.ip和端口号错误// client.Connect(remoteEp);//同步链接,阻塞主线程,会造成主页面卡顿// client.ConnectAsync(remoteEp).Wait();//同步链接,使用wait()等待,也会造成主页面卡顿await client.ConnectAsync(remoteEp);label7.Text = "连接成功";button1.Text = "关闭";}catch (Exception ex){MessageBox.Show(ex.Message);return;}
}
//发送数据
private void button2_Click(object sender, EventArgs e)
{if (client == null||!client.Connected){label7.Text = "请先建立连接";return;}if (string.IsNullOrWhiteSpace(textBox1.Text)){label7.Text = "请先输入发送的内容,在发送";return;}
byte[] buffer = Encoding.UTF8.GetBytes(textBox1.Text);client.Send(buffer);label7.Text = "发送成功";
}