Day40-45 网络高级(modbus)

2024-03-15 23:20
文章标签 网络 高级 45 modbus day40

本文主要是介绍Day40-45 网络高级(modbus),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • Modbus起源
    • 1.起源:
    • 2.分类:
    • 3.优势:
    • 4.应用场景:
    • 5.ModbusTCP特点:
  • Modbus TCP协议格式
    • 1.报文头
    • 2.寄存器
    • 3.功能码
  • 工具软件使用
    • .Modbus Slave&Poll
    • 2.网络调试助手
    • .Wireshark的使用
  • Modbus RTU
    • 1、与Modbus TCP的区别
    • 2、Modbus RTU特点
    • 3.ModbusRTU协议格式:
    • 4.报文详解:
    • 5.模拟器的使用
      • 一、虚拟串口的安装
      • 二、虚拟机绑定端口
      • 三、测试通信
      • 四、将Modbus Slave模拟器作为RTU设备的从机
  • Modbus库
    • 【1】库的安装
      • 1.库的安装配置
      • 2.库的使用
    • 【2】函数接口
    • 【3】编程流程
  • 基于Modbus的工业数据采集项目
    • 1.Http简介
    • 2.Http特点
    • 3.Http协议格式
      • 客户端请求消息格式
        • a. 请求行:
        • b. 请求头:
        • c. 空行
        • d. 请求体
  • WebServer
    • 1.服务器源码分析:
    • 2.安装使用postman
    • 3.结合Modbus部分整体流程分析

Modbus起源

1.起源:

Modbus由Modicon公司于1979年开发,是一种工业现场总线协议标准。
Modbus通信协议具有多个变种,其中有支持串口,以太网多个版本,其中最著名的是Modbus RTU、Modbus ASCII和Modbus TCP三种
其中Modbus TCP是在施耐德收购Modicon后1997年发布的。

2.分类:

1)Modbus RTU:
运行在串口上的协议,采用二进制表现形式以及紧凑型数据结构,通信效率高,应用广泛
2)Modbus ASCII:
运行在串口上的协议,采用ASCII码传输,并且利用特殊字符作为其字节的开始与结束标识,其传输效率要远远低于Modbus RTU协议,一般只有在通信数据量较小的情况下才考虑使用Modbus ASCII通信协议
3)Modbus TCP:
运行在以太网上的协议

3.优势:

 免费、简单、容易使用

4.应用场景:

Modbus协议是现在国内工业领域应用最多的协议,不只PLC设备,各种终端设备,比如水控机、水表、电表、工业秤、各种采集设备

5.ModbusTCP特点:

1.采用主从问答方式进行通信
2.ModbusTCP是应用层协议,基于传输层TCP进行传输的
3.ModbusTCP端口号默认为502

Modbus TCP协议格式

ModbusTcp协议包含三部分:报文头、功能码、数据
在这里插入图片描述

Modbus TCP/IP协议最大数据帧长度为260字节

1.报文头

包含7个字节,分别是:
在这里插入图片描述

2.寄存器

包含四种:离散量输入、线圈、输入寄存器、保持寄存器
1)离散量和线圈其实就是位寄存器(每个寄存器数据占1字节),工业上主要用于控制IO设备。
线圈寄存器,类比为开关量,每一个bit都对应一个信号的开关状态。所以一个byte就可以同时控制8路的信号。比如控制外部8路io的高低。 线圈寄存器支持读也支持写,写在功能码里面又分为写单个线圈寄存器和写多个线圈寄存器。
对应上面的功能码也就是:0x01 0x05 0x0f
离散输入寄存器,离散输入寄存器就相当于线圈寄存器的只读模式,他也是每个bit表示一个开关量,而他的开关量只能读取输入的开关信号,是不能够写的。比如我读取外部按键的按下还是松开。
所以功能码也简单就一个读的 0x02
2)输入和保持寄存器是字寄存器(每个寄存器数据占2个字节),工业上主要用于存储工业设备的值。
保持寄存器,这个寄存器的单位不再是bit而是两个byte,也就是可以存放具体的数据量的,并且是可读写的。比如我我设置时间年月日,不但可以写也可以读出来现在的时间。写也分为单个写和多个写
所以功能码有对应的三个:0x03 0x06 0x10
输入寄存器,这个和保持寄存器类似,但是也是只支持读而不能写。一个寄存器也是占据两个byte的空间。类比我我通过读取输入寄存器获取现在的AD采集值
对应的功能码也就一个 0x04

3.功能码

在这里插入图片描述
具体协议分析可参考:
http://www.360doc.com/content/20/0804/12/43769266_928452485.shtml

读数据:
主机->从机:报文头(7) + 功能码(1) + 起始地址(2)+ 数量(2)
从机->主机:报文头(7) + 功能码(1) + 字节计数(1)+ 数据(?)

写单个:
主机->从机:报文头(7) + 功能码(1) + 地址(2)+ 数据/断通标志(2)

写多个:
主机->从机:报文头(7) + 功能码(1) + 起始地址(2)+ 数量(2)+字节计数(1)+数据(?)

练习:读传感器数据,读1个寄存器数据,写出主从数据收发协议。
主机给从机:
|-事务处理标识符|-协议类型-|-字节长度-|-从机ID-|-功能码-|-起始地址-|-寄存器个数-|
0x0000 0x0000 0x0006 0x01 0x03 0x0000 0x0001
|-事务处理标识符|-协议类型-|-字节长度-|-从机ID-|-功能码-|-数据长度-|-寄存器数据-|
0x0000 0x0000 0x0005 0x01 0x03 0x02 0x0102

工具软件使用

.Modbus Slave&Poll

1)软件默认安装
2)破解
点击connection->connect,输入序列号即可
3)使用
先设置
在这里插入图片描述
后连接(连接时注意先开启slave端(相当于服务器),后起poll端(相当于客户端))
在这里插入图片描述查询windows IP:

win r 输入cmd
输入 ipconfig

2.网络调试助手

在这里插入图片描述

.Wireshark的使用

捕获器选择:
windows如果连接有线网络,选择本地连接/以太网
如果连接无线网络,选择WLAN
如果只是在本机上的通信,选择NPCAP Loopback apdater
或Adapter for loopback traffic capture
过滤条件:
过滤端口:tcp.port==502
过滤IP:ip.addr == 192.168.3.11(windows 的ip)
在这里插入图片描述
在这里插入图片描述

Modbus RTU

1、与Modbus TCP的区别

在一般工业场景使用modbus RTU的场景还是更多一些,modbus RTU基于串行协议进行收发数据,包括RS232/485等工业总线协议。
与modbus TCP不同的是RTU没有报文头MBAP字段,但是在尾部增加了两个CRC检验字节(CRC16),因为网络协议中自带校验,所以在TCP协议中不需要使用CRC校验码。
RTU和TCP的总体使用方法基本一致,只是在创建modbus对象时有所不同,TCP需要传入网络socket信息;而RTU需要传入串口相关信息。

2、Modbus RTU特点

ModbusRTU也是主从问答协议,由主机发起,一问一答
设置串口参数:
设置串口参数时要求:
波特率为9600
8位数据位
1位停止位
无流控

3.ModbusRTU协议格式:

ModbusRTU协议数据帧包含四部分:地址码、功能码、数据、校验码
地址码:从机ID 1-247
功能码:同ModbusTCP协议
数据:起始地址、数量、数据
校验码:2字节,对地址码、功能码、数据部分进行校验,调用函数自动生成

4.报文详解:

03功能码:
主机->从机: 01 03 00 00 00 01 84 0A
01:从机ID
03:功能码
00 00:起始地址
00 01:数量
84 0A:校验码

从机->主机:01 03 02 00 14 b8 44
1.01:从机ID
03:功能码
02: 字节计数
00 14:数据
b8 44 :校验码

参考示例:
https://blog.csdn.net/qq153471503/article/details/124317894

5.模拟器的使用

由于实际硬件产品成本较高,我们这里可以使用Modbus软件模拟器,进行数据模拟从而分析Modbus协议。
使用工具:

  1. ModbusPoll(模拟主机)和ModbusSlave(模拟从机)
  2. vspd虚拟串口
  3. UartAssist串口调试工具
    设置串口参数要求:波特率为9600 8位数据位 1位停止位 无流控 无校验
    虚拟串口的使用:

一、虚拟串口的安装

1.将压缩包解压后,双击vspd.exe文件进行安装
在这里插入图片描述
2.安装完成后,找到安装目录,将Cracked下的文件复制到软件安装目录

3.打开软件,添加com1和com2端口(用完记得删除端口)
4.添加完端口后,打开设备管理器,这里出现如下图所示即可。

在这里插入图片描述

二、虚拟机绑定端口

  1. 将虚拟机在系统关机(必须是关机状态,挂起不行)状态下,点击虚拟机->设置->硬件->添加串行端口,添加COM1
    2.添加完成后,第一次使用需要将电脑重启
    3.重启之后,开启虚拟机,点击虚拟机->可移动设备->串行端口->连接
    4.当连接上虚拟串口后,在终端输入dmesg | grep tty,可以查看到对应的设备文件,其中默认的会有ttyS0文件,剩下的就是虚拟串口对应的设备文件

三、测试通信

1.Windows打开串口调试工具,选择好串口COM2->COM1,设置对应的波特率
在这里插入图片描述
2.在虚拟机运行minicom
在虚拟机安装minicom软件
sudo apt-get install minicom
在终端执行sudo minicom -s
1)选择serial port setup,回车
在这里插入图片描述2)设置设备文件,波特率,关闭流控,按如下图设置(文件改成自己的)

在这里插入图片描述
3)修改完成后,回车,保存修改,选择save setup as dfl,敲回车,再次选择exit回车
在这里插入图片描述4)退出后就可以和windows下的串口调试工具进行通信测试
5)也可以在这个界面输入字符,查看串口助手的显示情况。

在这里插入图片描述
6)退出:ctrl+A、Z,在弹出的界面里输入X 回车,即可退出。

四、将Modbus Slave模拟器作为RTU设备的从机

虚拟机绑定COM1端口,slave连接COM2端口,虚拟机通过编程测试串口通信
Modbus Slave端的配置如下:
在这里插入图片描述

Modbus库

【1】库的安装

1.库的安装配置

1.在linux中解压压缩包
tar -xvf libmodbus-3.1.7.tar.gz
2.进入源码目录,创建文件夹(存放头文件、库文件)
cd libmodbus-3.1.7
mkdir install
3.执行脚本configure,进行安装配置(指定安装目录)
./configure --prefix=$PWD/install
4.执行make和make install
make//编译
make install//安装
执行完成后会在install文件夹下生产对应的头文件、库文件件夹。install用于存放产生的头文件、库文件等

2.库的使用

要想编译方便,可以将头文件和库文件放到系统路径下
sudo cp install/include/modbus/.h /usr/include
sudo cp install/lib/
-r /lib -d
后期编译时,可以直接gcc xx.c -lmodbus
头文件默认搜索路径:/usr/include 、/usr/local/include
库文件默认搜索路径:/lib、/usr/lib

【2】函数接口

modbus_t*   modbus_new_tcp(const char *ip, int port)
功能:以TCP方式创建Modbus实例,并初始化
参数:ip   :ip地址port:端口号
返回值:成功:Modbus实例失败:NULL
int modbus_set_slave(modbus_t *ctx, int slave)
功能:设置从机ID
参数:ctx   :Modbus实例slave:从机ID
返回值:成功:0失败:-1
int   modbus_connect(modbus_t *ctx)
功能:和从机(slave)建立连接
参数:ctx:Modbus实例
返回值:成功:0失败:-1
void   modbus_free(modbus_t *ctx)
功能:释放Modbus实例
参数:ctx:Modbus实例
void   modbus_close(modbus_t *ctx)
功能:关闭套接字
参数:ctx:Modbus实例
int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest)
功能:读取线圈状态,可读取多个连续线圈的状态(对应功能码为0x01)
参数:ctx   :Modbus实例addr :寄存器起始地址nb    :寄存器个数dest :得到的状态值
int  modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest)
功能:读取输入状态,可读取多个连续输入的状态(对应功能码为0x02)
参数:ctx   :Modbus实例addr :寄存器起始地址nb   :寄存器个数dest :得到的状态值
返回值:成功:返回nb的值
int  modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest)
功能:读取保持寄存器的值,可读取多个连续保持寄存器的值(对应功能码为0x03)
参数:ctx   :Modbus实例addr :寄存器起始地址nb    :寄存器个数dest :得到的寄存器的值
返回值:成功:读到寄存器的个数失败:-1
int   modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest)
功能:读输入寄存器的值,可读取多个连续输入寄存器的值(对应功能码为0x04)
参数:ctx   :Modbus实例addr :寄存器起始地址nb    :寄存器个数dest :得到的寄存器的值
返回值:成功:读到寄存器的个数失败:-1
int  modbus_write_bit(modbus_t *ctx, int addr, int status);
功能:写入单个线圈的状态(对应功能码为0x05)
参数:ctx     :Modbus实例addr  :线圈地址status:线圈状态
返回值:成功:0失败:-1
int  modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src);
功能:写入多个连续线圈的状态(对应功能码为15)
参数:ctx     :Modbus实例addr  :线圈地址nb     :线圈个数src    :多个线圈状态
返回值:成功:0失败:-1
int  modbus_write_register(modbus_t *ctx, int addr, int value);
功能:  写入单个寄存器(对应功能码为0x06)
参数: ctx    :Modbus实例addr  :寄存器地址value :寄存器的值 
返回值:成功:0失败:-1
int  modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src);
功能:写入多个连续寄存器(对应功能码为16)
参数:ctx    :Modbus实例addr  :寄存器地址nb     :寄存器的个数src    :多个寄存器的值 
返回值:成功:0失败:-1

【3】编程流程

1.创建实例
modbus_new_tcp
2.设置从机ID
modbus_set_slave
3.连接
modbus_connect
4.读写操作
调用功能码对应函数
5.关闭套接字
modbus_close
6.释放示例
modbus_free

基于Modbus的工业数据采集项目

1.Http简介

HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于Web Browser(浏览器)到Web Server(服务器)进行数据交互的传输协议。
HTTP是应用层协议
HTTP是一个基于TCP通信协议传输来传递数据(HTML 文件, 图片文件, 查询结果等)
HTTP协议工作于B/S架构上,浏览器作为HTTP客户端通过URL主动向HTTP服务端即WEB服务器发送所有请求,Web服务器根据接收到的请求后,向客户端发送响应信息。
HTTP默认端口号为80,但是你也可以改为8080或者其他端口

2.Http特点

HTTP是无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
HTTP是媒体独立的:这意味着,只要客户端和服务器知道如何处理的数据内容,任何类型的数据都可以通过HTTP发送。客户端以及服务器指定使用适合的MIME-type内容类型。
HTTP是无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

3.Http协议格式

客户端请求消息格式

客户端发送一个HTTP请求到服务器的请求消息包括以下格式:请求行、请求头部、空行和请求数据四个部分组成,下图给出了请求报文的一般格式。
在这里插入图片描述

a. 请求行:

请求行是由请求方法字段、url字段、http协议版本字段3个部分组成。请求行定义了本次请求的方式,格式如下:GET /example.html HTTP/1.1(CRLF)。

http的请求方式:
http协议中共定义了八种数据的请求方法。分别是:OPTIONS、HEAD、GET、POST、PUT、DELETE、TRACE、CONNECT;我们在实际应用中常用的也就是 get 和 post,其他请求方式也都可以通过这两种方式间接的来实现。
(增POST 删DELETE 改PUT 查GET)
GET方法和POST方法的区别?
GET通常用来从服务器上获得数据,而非修改信息;POST用来向服务器传递数据。
1.请求数据带参数,;GET请求的数据会附加在URL之后,以?分割URL和传输数据,多个参数用&连接。POST请求会把请求的数据放置在HTTP请求包的包体中。
因此,GET请求的数据会暴露在地址栏中,而POST请求则不会。
2.传输数据的大小;在HTTP规范中,没有对URL的长度和传输的数据大小进行限制。但是在实际开发过程中,对于GET,特定的浏览器和服务器对URL的长度有限制。因此,在使用GET请求时,传输数据会受到URL长度的限制。对于POST,由于不是URL传值,理论上是不会受限制的,但是实际上各个服务器会规定对POST提交数据大小进行限制,Apache、IIS都有各自的配置
3.GET请求返回的内容可以被浏览器缓存起来。而每次提交的POST,浏览器在你按 下F5的时候会跳出确认框,浏览器不会缓存POST请求返回的内容
4.GET对数据进行查询,POST主要对数据进行增删改!简单说,GET是只读,POST是写
5.对于参数的数据类型,get只接受ASCII字符,而post没有限制。

b. 请求头:

也被称作消息报头,请求头是由一些键值对组成,每行一对,关键字和值用英文冒号“:”分隔。允许客户端向服务器发送一些附加信息或者客户端自身的信息,典型的请求头如下:
Accept:作用:描述客户端希望接收的 响应body 数据类型;示例:Accept:text/html
Accept-Charset:作用:浏览器可以接受的字符编码集;示例:Accept-Charset:utf-8
Accept-Language:作用:浏览器可接受的语言;示例:Accept-Language:en
Connection:作用:表示是否需要持久连接,注意HTTP1.1默认进行持久连接;示例:Connection:close
Content-Length:作用:请求的内容长度:示例:Content-Length:348
Content-Type:作用:描述客户端发送的 body 数据类型

c. 空行

最后一个请求头之后是一个空行,发送回车符和换行符,通知服务器以下不再有请求头。

d. 请求体

请求数据:请求数据不在GET方法中使用,而是在POST方法中使用。POST方法适用于需要客户填写表单的场合。与请求数据相关的最常使用的请求头是Content-Type和Content-Length。

WebServer

简单TCP服务器示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>#define PORT 8080
#define BUFFER_SIZE 1024void handle_request(int client_socket) {char buffer[BUFFER_SIZE];char response[] = "HTTP/1.1 200 OK\nContent-Type: text/html\n\n<html><body><h1>Hello, World!</h1></body></html>";// 从客户端读取请求ssize_t bytes_read = read(client_socket, buffer, BUFFER_SIZE - 1);if (bytes_read == -1) {perror("读取请求失败");return;}buffer[bytes_read] = '\0';// 打印请求内容printf("收到请求:\n%s\n", buffer);// 发送响应给客户端ssize_t bytes_written = write(client_socket, response, strlen(response));if (bytes_written == -1) {perror("发送响应失败");}
}int main() {int server_socket, client_socket;struct sockaddr_in server_address, client_address;socklen_t client_address_len;//创建套接字if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {perror("创建套接字失败");exit(1);}//设置地址重用int reuse = 1;if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) {perror("设置地址重用失败");exit(1);}//初始化绑定地址server_address.sin_family = AF_INET;server_address.sin_port = htons(PORT);server_address.sin_addr.s_addr = htonl(INADDR_ANY);if (bind(server_socket, (struct sockaddr *)&server_address, sizeof(server_address)) == -1) {perror("绑定地址失败");exit(1);}//启动监听if (listen(server_socket, 10) == -1) {perror("启动监听失败");exit(1);}printf("服务器已启动,监听端口 %d\n", PORT);// 接受连接并处理请求while (1) {client_address_len = sizeof(client_address);if ((client_socket = accept(server_socket, (struct sockaddr *)&client_address, &client_address_len)) == -1) {perror("接受连接失败");continue;}printf("接受新连接\n");// 处理请求handle_request(client_socket);// 关闭客户端套接字close(client_socket);printf("连接已关闭\n");}// 关闭服务器套接字close(server_socket);return 0;
}

1.服务器源码分析:

1.初始化服务器
2.循环等等待连接,连接后创建线程,调用线程函数msg_request,再函数中调用
handler_msg函数分析请求
3.handler_msg函数中,先查看请求内容,其次获取请求方法、URL、参数,判断请求方法是什么,对need_handler赋值,确定请求资源路径,如果请求地址没有携带任何资源,则默认返回index.html文件,如果资源不存在,返回404,如果需要处理(get请求带参数,post请求)调用handle_request函数,如果不需要(get请求不带参数且资源存在),调用echo_www函数,直接返回资源
4.handle_request函数主要用来获取post请求正文数据,调用parse_and_process函数处理正文内容(需要自己额外添加函数)

2.安装使用postman

在这里插入图片描述

3.结合Modbus部分整体流程分析

在这里插入图片描述

这篇关于Day40-45 网络高级(modbus)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/813593

相关文章

如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解

《如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解》:本文主要介绍如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别的相关资料,描述了如何使用海康威视设备网络SD... 目录前言开发流程问题和解决方案dll库加载不到的问题老旧版本sdk不兼容的问题关键实现流程总结前言作为

深入解析Spring TransactionTemplate 高级用法(示例代码)

《深入解析SpringTransactionTemplate高级用法(示例代码)》TransactionTemplate是Spring框架中一个强大的工具,它允许开发者以编程方式控制事务,通过... 目录1. TransactionTemplate 的核心概念2. 核心接口和类3. TransactionT

SSID究竟是什么? WiFi网络名称及工作方式解析

《SSID究竟是什么?WiFi网络名称及工作方式解析》SID可以看作是无线网络的名称,类似于有线网络中的网络名称或者路由器的名称,在无线网络中,设备通过SSID来识别和连接到特定的无线网络... 当提到 Wi-Fi 网络时,就避不开「SSID」这个术语。简单来说,SSID 就是 Wi-Fi 网络的名称。比如

Java实现任务管理器性能网络监控数据的方法详解

《Java实现任务管理器性能网络监控数据的方法详解》在现代操作系统中,任务管理器是一个非常重要的工具,用于监控和管理计算机的运行状态,包括CPU使用率、内存占用等,对于开发者和系统管理员来说,了解这些... 目录引言一、背景知识二、准备工作1. Maven依赖2. Gradle依赖三、代码实现四、代码详解五

Python中列表的高级索引技巧分享

《Python中列表的高级索引技巧分享》列表是Python中最常用的数据结构之一,它允许你存储多个元素,并且可以通过索引来访问这些元素,本文将带你深入了解Python列表的高级索引技巧,希望对... 目录1.基本索引2.切片3.负数索引切片4.步长5.多维列表6.列表解析7.切片赋值8.删除元素9.反转列表

正则表达式高级应用与性能优化记录

《正则表达式高级应用与性能优化记录》本文介绍了正则表达式的高级应用和性能优化技巧,包括文本拆分、合并、XML/HTML解析、数据分析、以及性能优化方法,通过这些技巧,可以更高效地利用正则表达式进行复杂... 目录第6章:正则表达式的高级应用6.1 模式匹配与文本处理6.1.1 文本拆分6.1.2 文本合并6

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

ASIO网络调试助手之一:简介

多年前,写过几篇《Boost.Asio C++网络编程》的学习文章,一直没机会实践。最近项目中用到了Asio,于是抽空写了个网络调试助手。 开发环境: Win10 Qt5.12.6 + Asio(standalone) + spdlog 支持协议: UDP + TCP Client + TCP Server 独立的Asio(http://www.think-async.com)只包含了头文件,不依

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

poj 3181 网络流,建图。

题意: 农夫约翰为他的牛准备了F种食物和D种饮料。 每头牛都有各自喜欢的食物和饮料,而每种食物和饮料都只能分配给一头牛。 问最多能有多少头牛可以同时得到喜欢的食物和饮料。 解析: 由于要同时得到喜欢的食物和饮料,所以网络流建图的时候要把牛拆点了。 如下建图: s -> 食物 -> 牛1 -> 牛2 -> 饮料 -> t 所以分配一下点: s  =  0, 牛1= 1~