微服务实战之春云与刀客(五)—— spring cloud与docker swarm集群
概述
微服务与docker结合是必然的趋势,本文介绍spring cloud与docker swarm集群实现微服务极简部署,不需要编写Dockerfile,不需要docker-compose编排容器。
上一篇文章已经介绍了docker swarm的环境搭建,这里不再叙述。
主要包含步骤:
- 结合maven docker 插件直接编译jar 包,生成和推送应用镜像。
- 通过docker swarm 命令创建服务。
- 线下和线上结合,自动化部署
制作java基础镜像
java镜像是spring boot应用的基础,这里基于openjdk:8,加入了时区,制作成了openjdk-tiejia:8
- 新建Dockerfile
FROM openjdk:8 RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \ echo 'Asia/Shanghai' >/etc/timezone
- 生成镜像
docker build -t 192.168.0.37:5000/openjdk-tiejia:8 - 推送
docker push 192.168.0.37:5000/openjdk-tiejia:8
docker-maven-plugin 插件与规范
docker-maven-plugin 插件可以通过maven生成镜像,作用跟Dockerfile类似。
docker-maven-plugin也很简单:先编译java项目生成jar包,然后加入到openjdk-tiejia:8 镜像,生成新的镜像,最终新的镜像就是java环境+jar包。
spring cloud maven 项目结构(可以参考之前几篇文章)
下面以finance金融微服务来说明。
- 公共父级pom文件
cehome-cloud-parent-0.0.1-SNAPSHOT.pom 是所有项目的公共父级pom文件 ,里面包含 spring boot/cloud 版本信息和 引用了docker maven 插件。这样的好处无须在每个项目都引入docker maven 插件。 - 项目目录结构
每个微服务都包含了api和service两个模块,api是接口定义,service是代码实现。
spring_cloudfinancepom.xml:项目父pom模块
spring_cloudfinancefinance-servicepom.xml: 主体服务
spring_cloudfinancefinance-apipom.xml: 接口定义
pom详情以及docker-maven-plugin 插件使用
也就是说,有4中pom文件,分别是公共父pom、项目父pom、api定义pom、service实现pom
1)公共父pom
这个文件除了定义spring cloud 依赖,还包含了 docker-maven-plugin(https://github.com/spotify/docker-maven-plugin),插件说明可以直接查看xml中的注释。此插件对应命令为 mvn package docker:build 。
在properties中设置开关属性skipDockerBuild=true ,意思是缺省忽略docker编译。一般都多模块的项目只有主模块需要生成镜像,其它是不需要的,所以缺省是忽略。例如我们的项目api模块不需要DockerBuild,只有service模块需要生成的spring boot jar包、需要打镜像,则在properties中设置skipDockerBuild为false即可。
插件配置entryPoint的java命令我们已经加入了部分固定的jvm参数,
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.cehome.cloud</groupId> <artifactId>cehome-cloud-parent</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>pom</packaging> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.7.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <mybatis-version>1.3.0</mybatis-version> <skipDockerBuild>true</skipDockerBuild> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>1.5.7.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.SR3</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <distributionManagement> <repository> <id>internal-releases</id> <name>Local Release Repository</name> <url>http://192.168.0.12:8080/nexus/content/repositories/releases/</url> </repository> <snapshotRepository> <id>internal-snapshots</id> <name>Local Snapshot Repository</name> <url>http://192.168.0.12:8080/nexus/content/repositories/snapshots/</url> </snapshotRepository> </distributionManagement> <build> <finalName>${project.artifactId}</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>com.spotify</groupId> <artifactId>docker-maven-plugin</artifactId> <version>0.4.13</version> <configuration> <!-- skipDockerBuild 是开关,skipDockerBuild=true ,意思是忽略docker编译 --> <skipDockerBuild>${skipDockerBuild}</skipDockerBuild> <!-- 随便起名 --> <imageName>192.168.0.37:5000/cehome/${project.artifactId}</imageName> <!-- 基础镜像,这里用java 8,也可以 java或java:7 --> <baseImage>192.168.0.37:5000/openjdk-tiejia:8</baseImage> <!-- 启动后执行的命令 --> <entryPoint>["java","-verbose:gc", "-Xloggc:/root/logs/gc.log", "-XX:+PrintGCTimeStamps", "-XX:+PrintGCDetails","-XX:+HeapDumpOnOutOfMemoryError", "-XX:HeapDumpPath=/root/dump","-Dsystem.out.filename=/root/logs/%tF.out" ]</entryPoint> <!-- 往基础镜像里面拷贝的资源,这里只拷贝编译后的jar --> <resources> <resource> <targetPath>/</targetPath> <directory>${project.build.directory}</directory> <include>${project.build.finalName}.jar</include> </resource> </resources> </configuration> </plugin> </plugins> </build> </project>
2)项目父pom
只需要集成公共父pom、包含finance-api、finance-service模块。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.cehome.cloud</groupId> <artifactId>cehome-cloud-parent</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>finance</artifactId> <packaging>pom</packaging> <modules> <module>finance-api</module> <module>finance-service</module> </modules> </project>
3)api定义pom
引入了公共父pom、依赖feign , 还有一个spring-boot-thin-layout 插件作用是编译成普通jar包而不是spring boot肥jar。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.cehome.cloud</groupId> <artifactId>cehome-cloud-parent</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>finance-api</artifactId> <packaging>jar</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot.experimental</groupId> <artifactId>spring-boot-thin-layout</artifactId> <version>1.0.5.RELEASE</version> </dependency> </dependencies> </plugin> </plugins> </build> </project>
3)service实现pom
继承项目父pom。
它是生成镜像的模块,需要设置属性
<skipDockerBuild>false</skipDockerBuild>
依赖spring cloud 模块、依赖finance-api接口模块。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.cehome.cloud</groupId> <artifactId>finance</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>finance-service</artifactId> <packaging>jar</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <skipDockerBuild>false</skipDockerBuild> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.cehome.cloud</groupId> <artifactId>finance-api</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies> </project>
maven 编译、生成和推送镜像
mvn clean package docker:build -U -DpushImage -DdockerImageTags -DdockerImageTags=`date +%Y%m%d`
-DdockerImageTags 为镜像tag,这里用了当前日期变量(如:20171125)
-DpushImage 指生成镜像后还继续推送镜像,镜像的目标地址在公共父pom中已经指定好了(192.168.0.37:5000/cehome/${project.artifactId}),这个镜像在后面创建服务的时候需要用到。
部署 eureka注册中心
注册中心建议通过单机方式来部署
- eureka项目代码开发
代码略,eureka是个单模块的项目,只给出pom文件
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.cehome.cloud</groupId> <artifactId>cehome-cloud-parent</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <properties> <!-- build docker images--> <skipDockerBuild>false</skipDockerBuild> </properties> <artifactId>eureka</artifactId> <packaging>jar</packaging> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency> </dependencies> </project>
- maven编译和推送镜像
- clean package docker:build -U -DpushImage -DdockerImageTags -DdockerImageTags=
date +%Y%m%d
- 在0.37/0.38两台机器分别执行如下代码启动注册中心
docker pull 192.168.0.37:5000/cehome/eureka
docker stop eureka
docker kill eureka
docker run -itd --rm --net=host --hostname vm-eureka --name eureka 192.168.0.37:5000/cehome/eureka\
-Xms512m -Xmx512m -XX:MaxMetaspaceSize=256m -jar ./eureka.jar
- 注意问题:eureka 两个节点是互为注册,eureka.client.serviceUrl.defaultZone 参数不能包含两个节点的url,只能是对方的url,例如在0.37上,defaultZone要指向0.38, 参考:
eureka.client.fetch-registry=false eureka.client.register-with-eureka=true eureka.client.serviceUrl.defaultZone=http://192.168.0.38:8761/eureka/ logging.level.root=info server.port=8761 spring.application.name=eureka
为了保持一份代码,一种方式是java 命令行中带上了spring boot支持的 --eureka.client.serviceUrl.defaultZone参数;另一个办法就是在ureka.client.serviceUrl.defaultZone配上两个地址,然后在代码中动态去掉本机的地址,这个稍微麻烦。
- 访问 192.168.0.37:8761
看到ds replicas 和下面的registered-replicas、available-replicas指向0.38就是对了。
同样访问192.168.0.38:8761,ds replicas等指向0.37才对。
集群服务部署
这里用operation运营微服务来说明。
生成、推送镜像
- 进入服务目录
- spring_cloud/operation
- 生成、推送镜像
- clean package docker:build -U -DpushImage -DdockerImageTags -DdockerImageTags=
date +%Y%m%d
第一次部署服务(创建服务)
docker service create \ --replicas 2 \ --name operation-service\ --network tiejia \ --publish 8804:8804\ --hostname="vm-{{.Service.Name}}-{{.Task.Slot}}" \ --mount type=volume,src={{.Service.Name}}-{{.Task.Slot}},dst=/root \ --detach=false \ 192.168.0.37:5000/cehome/operation-service\ -Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m -jar ./operation-service.jar
命令说明:
docker service create //创建服务命令 --replicas 2 // 两个节点 --name operation-service //服务名称 --network tiejia //服务使用网络,参考前一篇文章中的网络创建 --publish 8804:8804 //对外:对内端口映射 //{{.Service.Name}} 指向--name,即operation-service;{{.Task.Slot}}指节点编号:1,2 --hostname="vm-{{.Service.Name}}-{{.Task.Slot}}" // 目录映射 --mount type=volume,src={{.Service.Name}}-{{.Task.Slot}},dst=/root --detach=false 192.168.0.37:5000/cehome/operation-service //镜像地址 -Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m -jar ./operation-service.jar //java 参数
hostname、mount 两个参数可以不用
mount type=volume 方式会自动创建指定的目录,但必须挂载在/var/lib/docker/volumes/ 路径下;type=bind 方式需要手工创建目标目录,但可以是任意路径。微服务涉及多个节点,用volume 不用手工去创建目录了。
第二次部署服务(更新服务)
docker service update \ --update-delay 40s\ --detach=false\ operation-service
当原有镜像有修改则会重新部署,否则不会部署。
可以加入 --force 参数,不管镜像更新不更新都会重启。
--update-delay 两个节点启动间隔。这个不会判断第一个节点是否启动完毕了,只是第一个节点开始部署40秒后就部署第二个节点。后面会讲到如何避免此类问题。
伸缩服务节点
docker service scale --detach=false operation-service=3
回滚到上一版本
--rollback 只能回滚到上一次执行 docker service update 之前的状态,并不能无限制地回滚
docker service rollback operation-service
或
docker service update --rollback operation-service
回滚到任意版本
前面push镜像时(查dockerImageTags)都会打上了一个日期的tag,通过这个tag可以重新启动任意日期的版本,达到回滚的目的。
- 查看已有的版本
- images
- 启动20180725版本
docker service update \ --image 192.168.0.37:5000/cehome/operation-service:20180725\ --update-delay 40s\ --detach=false\ operation-service
重新修改java 参数
docker service update --args "-Xms512m -Xmx512m -XX:MaxMetaspaceSize=256m -jar ./operation-service.jar" --detach=false operation-service
查看集群日志
docker service logs operation-service
线下和线上结合,自动化部署
方案实施
上面介绍的内容可以认为是线下环境,我们还需要考虑线下、线上结合Jenkins实现自动化部署。
- 线下通过Jenkins 实现svn或git拉取代码、maven编译jar包和生成、推送镜像。
- 通过 Jenkins来调用docker service 命令 ,实现线下自动化部署。
- 部署后进行线下测试。
- 测试完毕后,通过Jenkins进行预发和线上环境的部署。
注意问题:
- 我们所有项目都使用配置中心来管理线下和线上的配置,代码和配置是分离的。这样只需要线下打包(生成镜像)一次就能线上直接使用,从效率和安全方面都得到提高。
- 线上也需要访问私有镜像仓库,以便拉取镜像启动服务。如果线上无法访问私有镜像仓库,则需要在线上单独创建一个私有镜像仓库,从线下在push到线上去
镜像打上线上dockerhub.tiejia.com标签 docker tag 192.168.0.37:5000/cehome/eureka dockerhub.tiejia.com/cehome/eureka 推送,第一次推送会慢一些,第二次是增量的,只把添加到镜像的jar包上传。 docker push dockerhub.tiejia.com/cehome/eureka
线上环境准备
预发环境集群至少需要1台机器,推荐3台机器,全部部署成manager节点。
生产环境集群至少需要3台生产机器,全部部署成manager节点。 manager需要奇数个以便选举主节点,推荐是7台
具体部署参考之前的文章。
微服务预发和生产环境区分
微服务通过eureka注册中心shi实现互相访问,所以在预发环境部署一套eureka,生产环境部署两个eureka。各服务分别连到预发或生产的eureka就可以自动区分开来。
镜像、容器维护
本地镜像、容器删除
docker system prune -a
-a, --all Remove all unused images not just dangling ones
私服镜像维护
查看所有镜像(忽略版本)
http://192.168.0.37:5000/v2/_catalog
{"repositories":["cehome/account-service","cehome/audit-service","cehome/call-center-service","。。。
查看某一个镜像
http://192.168.0.37:5000/v2/cehome/account-service/tags/list
{"name":"cehome/account-service","tags":["20180408","latest","20180410","20180411","20180413",
清除旧镜像
- 安装pip
yum -y install epel-release
yum install python-pip
pip install --upgrade pip
https://blog.csdn.net/yulei_qq/article/details/52984334
- 安装requests
pip install requests
- 安装清理主程序
https://github.com/burnettk/delete-docker-registry-image
1)安装
curl https://raw.githubusercontent.com/burnettk/delete-docker-registry-image/master/delete_docker_registry_image.py | sudo tee /usr/local/bin/delete_docker_registry_image >/dev/null
sudo chmod a+x /usr/local/bin/delete_docker_registry_image
2)修改 /usr/local/bin/delete_docker_registry_image,找到registry_data_dir 改为实际的私服存储路径(也可以在环境变量REGISTRY_DATA_DIR指定):
if 'REGISTRY_DATA_DIR' in os.environ:
registry_data_dir = os.environ['REGISTRY_DATA_DIR'] else: registry_data_dir = "/root/hub/docker/registry/v2"
requests 模块在下面的工具要依赖。
- 继续安装清理脚本
curl https://raw.githubusercontent.com/burnettk/delete-docker-registry-image/master/clean_old_versions.py | sudo tee /usr/local/bin/clean_old_versions >/dev/null
sudo chmod a+x /usr/local/bin/clean_old_versions
- 执行
clean_old_versions --image '^.*' --exclude 'latest' -l 2 --registry-url http://192.168.0.37:5000
clean_old_versions --image '^cehome/user-service' --exclude 'latest' -l 2 --registry-url http://192.168.0.37:5000
{"name":"cehome/user-service","tags":["latest","20180627","20180705"]}
实践问题
docker limit问题
ulimit -n
centos7.2宿主机缺省是1024需要设置,docker容器缺省是65536可以不用设置
双物理机器,一台重启,当掉的服务会自动切换到另一台,第二台可能无法承受,如何处理?
自动启动服务本来这也是集群的一个优点,但对于仅2台机器来说则不太好。目前没找到禁止自动启动服务的办法,最好是集群有3台机器。
docker swarm 集群里面服务之间无法调用
1)部署operation-service 2个点后,到注册中心一看,只有一个点,地址是10.255.0.4,
2)进入容器发现有多个网卡,10.255.0.4这个网址在2个点都有,正确的应该是10.0.0.7
3)如何选择ip参考
http://www.mamicode.com/info-detail-1873672.html
具体的几个配置参考
http://blog.csdn.net/xichenguan/article/details/76557065
4)最终一种巧妙的解决办法,配置ip选择参数:
spring.cloud.inetutils.preferred-networks=none
none或随便其它非ip字符串则导致一个都ip都匹配不上!
最终结果让其忽略所有网卡ip,这样最终会取本地host:InetAddress.getLocalHost();
这个跟/etc/hosts 配置的一样,所以OK了。
附:
//前缀匹配10.0.0开头的ip
spring.cloud.inetutils.preferred-networks=10.0.0
//正则允许所以ip
spring.cloud.inetutils.preferred-networks=.+
健康检查与回滚
健康检查可以保证一个节点启动完毕才会启动另一个节点
docker service update --force --detach=false\
--health-cmd "curl --fail http://127.0.0.1:8820/startup-status?p=0 || exit 1" \
--health-interval 5s\ --health-retries=20 \ --health-timeout 2s\ gateway
1)url必须返回0,表示成功;curl一般用127.0.0.1和内部端口,用实际ip不行(因为命令是在docker里面执行的 )
2)上面表示每5秒执行一次,每次2秒超时,一共尝试20次。 超时必须设置大一些,否则超时后会不断重启
3)如果url错误导致启动失败可以--no-healthcheck 恢复:
docker service update --force --detach=false --no-healthcheck gateway
加上回滚参数:
如下面把端口8820改成8830肯定curl是会失败,则会回滚
docker service update --force --detach=false\ --health-cmd "curl --fail http://127.0.0.1:8830/startup-status?p=0 || exit 1" \ --health-interval 5s\ --health-retries=20 \ --health-timeout 2s\ --update-failure-action rollback\ gateway
--update-failure-action Action on update failure ("pause"|"continue"|"rollback")
缺省是paused
这个比--update-delay duration 保险,--update-delay 只是是两个点启动间隔,只是大概估计的时间,所以在健康检查上面的基础上加个几秒即可:--update-delay 5s
启动超时
加入健康检查后,如果重试若干次后超时,则会导致容器不断重启!!加入 restart-condition=none 来避免。
猜测:是app正常启动后有问题会触发update-failure-action;如果程序还没启动完就超时则触发restart-conditionjava
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
太简单!只学十分钟,Python菜鸟也能开发一个区块链客户端
区块链技术以其去中心化特性成为又一具有颠覆性特征的技术。Python作为一种面向对象的解释型计算机程序设计语言,因其具有丰富和强大的库,常被称为“胶水语言”,简单、易上手,是区块链技术爱好者快速学习区块链的首选之一。 本文作者Adil Moujahid 是世界IT服务企业排名前十、日本IT服务企业排名榜首的NTT DATA集团的数据科学家,对Python在区块链方向的应用有着十分深入的研究。 在这篇文章中,Adil Moujahid 由双重支付问题引出去中心化支付方案,介绍公钥密码学、Hash函数、挖矿等区块链核心概念,并详细阐述如何产生一个新区快、如何将新区快添加到区块链等问题,最后,利用Python实现基本的区块链和区块链客户端。 在了解区块链的核心概念之后,让Adil Moujahid 手把手,教你用Python实现区块链和区块链客户端的实操吧!干货满满! 可以说,区块链是自互联网诞生以来最重要和最具颠覆性的技术之一。作为比特币和其他加密货币背后的核心技术,区块链在过去几年获得了广泛关注。 区块链是一个分布式数据库,允许双方之间直接进行交易,而无需第三方权限,对银行、政府和市场等...
- 下一篇
C# 串口类SerialPort的使用方法
序言:最近做了一个智能体育项目——跆拳道积分系统,硬件部分会向软件传入振动值等数据,链接方式为串口,所以用到SerialPort类。 值得注意的是: DataReceived 方法,当串口缓冲区有数据时执行该方法。 ReceivedBytesThreshold属性决定了当串口读缓存中数据多少个时才触发DataReceived事件,默认为1。串口接收的指令可能是错误值,所以这块根据自己需求进行设置。 首先需要引用SerialPort using System.IO.Ports; 创建全局串口对象 SerialPort com; SerialPort配置,并打开端口进行接收数据 private void Form1_Load(object sender, EventArgs e) { com = new SerialPort("COM5"); //实例化SerialPort并设置COM口 com.BaudRate = 115200;//波特率 com.Parity = Parity.None;//无奇偶校验位 com.StopBits = StopBits.Two;//两个停止位 com....
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS8安装Docker,最新的服务器搭配容器使用
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS关闭SELinux安全模块
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- SpringBoot2整合Redis,开启缓存,提高访问速度
- MySQL8.0.19开启GTID主从同步CentOS8
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程