news 2026/2/8 5:30:18

CVI基于TCP的C/S例程学习心得

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CVI基于TCP的C/S例程学习心得

欲看图文版,请PC浏览器下载附件pdf。

我想实现两个exe之间的信息互通,豆包说用TCP,遂开始学习CVI2010 TCP的例程。
遗憾的是,CVI例程向来缺乏参考文档,于是用户极不容易入门原厂例程。尤其是TCP这样的例程,本来就牵涉了一个晦涩的网路通信协议,理解例程就需要同时开两个或两个以上的project,作为主从机对着干才有实效。我于是瞎蒙了两天,终于try出来一些名堂,并写成文档,供后来者快速理解。

一、 学习TCP/IP例程Message.cws
1, 找到CVI2010的TCP/IP例程Message.cws入口
该例程Message.cws在我笔记本上的完整路径名是C:\Users\Public\Documents\National Instruments\CVI2010\samples\tcp\Message.cws。下面是通过CVI的起始页面,搜索原厂例程的步骤。

2, CVI打开Message.cws
可见一个cws里面,包含了两个project,分别是Message,和MessageReader。由于Message是加粗了的,所以是当前激活的project,在CVI中直接运行的将是MessageWriter.c对应的exe。

这里我们还需要运行MessageReader.c对应的exe,就必须再运行一个CVI并打开Message.cws,然后鼠标右键点击MessageReader,选“Set Active Project”,之后这个MessageReader就变粗体了,成为当前project。

3, CVI运行Message.cws,从server端传数据到client端
豆包说,在该例程里,MessageReader是客户端,MessageWriter是服务器,所以两个exe的启动顺序是由讲究的,必须先运行服务器MessageWriter的exe。
如何区分哪个程序是Client,哪个程序是Server呢?豆包说应以代码里的实际函数为准:
谁调用了StartTCPServer(启动监听),谁就是服务器,就必须先启动;
谁调用了ConnectToTCPServer(发起连接),谁就是客户端,就必须后启动。
如果,我们错误地首先运行了客户端的MessageReader的exe,就会在运行到ConnectToTCPServer()函数时报错,Timeout error:

所以得老打老实地先运行服务器MessageWriter的exe,后运行客户端的MessageReader的exe,两个exe才能愉快地玩耍:

您观察得很敏锐!两个GUI背后的CMD黑窗,应该跟CVI的exe没有直接关系。但是为什么我会一起截屏呢?这是因为,我最开运行客户端的MessageWriter的exe,其界面上“Send Date”按键是失活的,不晓得为啥,例程源码中也没有说明,甚至没有提及应该首先运行哪个exe呢。不由得感慨——很多时候,一个工程师如果没有第三方的支援,就会卡死在万里长征的第一步。

还好有诲人不倦的豆包啊,豆包说有可能是其他进程已经率先占用了端口号10000,导致同样使用端口号10000的MessageWriter无法启动TCP服务器。于是我就按照豆包说的,输入查看端口10000是否被占用的指令:netstat -ano | findstr 10000,结果如下,果然是有个进程已经占用了本机10000号端口。然后还可以根据端口号输入指令tasklist | findstr xxxxx,来反查是哪个软件进程占用的,居然是百度云盘。

豆包说,要么把这个进程用任务管理器杀掉,要么修改CVI例程的端口号,从10000改到10001。两种方案我都试过了,都OK。前面黑窗背景的图就是杀掉YunDetectService.exe之后再运行例程的结果,下图是修改CVI例程源码的端口号到10001之后再运行的查询结果:

其中,
进程 ID 4188 是MessageWriter_dbg.exe(服务器端),它已经成功监听了10001端口(LISTENING表示服务器在等待连接)。
进程 ID 8756是MessageReader_dbg.exe(客户端),用临时端口 63310。

二、 学习TCP/IP例程 server.cws和client.cws
该例程是基于 TCP/IP 协议的客户端 - 服务器(C/S)通信经典例程,核心演示了如何利用CVI的 sockutil 库实现跨进程/跨设备的网络数据交互。
该例程在我笔记本的文件路径是C:\Users\Public\Documents\National Instruments\CVI2010\samples\tcp\server.cws和client.cws。下面是通过CVI的起始页面,搜索原厂例程的步骤。

先后运行server.cws和client.cws,当用户往文本框输入一条字符串之后回车,会发送到另一侧并显示出来:

Server.c解析
注意到,开篇#include <tcpsupp.h>,这是CVI专属TCP通信支撑库(RegisterTCPServer/ServerTCPRead等核心API)。
函数RegisterTCPServer (portNum, ServerTCPCB, 0) 是注册 TCP 服务器的核心API。其中,portNum是端口号比如10000,ServerTCPCB是回调函数。该函数的作用是让程序在指定端口监听客户端连接,并绑定 “TCP事件回调函数ServerTCPCB”—— 即后续所有 TCP事件(客户端连接、数据收发、断开)都通过该回调函数来响应。
函数ServerTCPWrite (g_hconversation, transmitBuf, strlen(transmitBuf), 1000) 是向已连接的TCP客户端发送数据的核心API,专门用于服务器端向客户端写入数据流。
函数dataSize = ServerTCPRead (g_hconversation, receiveBuf, dataSize, 1000) 是服务器端读取客户端发送数据的核心 API,负责从已连接的TCP客户端接收数据流。该函数一般是放在回调函数ServerTCPCB中被TCP_DATAREADY事件触发所调用。
UnregisterTCPServer (portNum) 是注销 TCP 服务器的核心API,是 RegisterTCPServer 的 “反向操作”—— 用于停止服务器对指定端口的监听、释放底层套接字资源、注销 TCP 事件回调。

Client.c解析
函数ConnectToTCPServer (&g_hconversation, portNum, tempBuf, ClientTCPCB, NULL, 5000) 是 TCP 客户端主动连接服务器的核心API,用于客户端程序向指定 IP+port的TCP服务器发起连接请求,并绑定客户端的TCP事件回调函数ClientTCPCB。
函数dataSize = ClientTCPRead (g_hconversation, receiveBuf, dataSize, 1000) 是 TCP客户端读取服务器发送数据的核心API,负责从已建立的 TCP 连接中接收服务器下发的流数据。该函数一般是放在回调函数ClientTCPCB中被TCP_DATAREADY事件触发所调用。
函数ClientTCPWrite (g_hconversation, transmitBuf, strlen(transmitBuf), 1000) < 0 是TCP客户端向服务器发送数据的核心API,负责将客户端缓冲区的数据通过已建立的TCP连接发送给服务器。

三、 学习TCP/IP例程 MultiClientServer.cws
CVI2010的MultiClientServer.cws例程是一个典型的多客户端TCP服务器演示程序,主要功能是展示如何实现一个服务器同时与多个客户端建立TCP连接并进行通信。其中,服务器端(Server):作为TCP服务器,启动后监听指定端口(如默认的5000),支持同时接收多个客户端的连接请求,并为每个客户端创建独立的通信线程。客户端(Client):可同时启动多个实例,每个客户端通过TCP协议连接到服务器,实现与服务器的双向数据交互。
该例程特点如下:
多客户端并发连接:服务器通过线程池(Cmt函数库)管理多个客户端连接,避免单个客户端阻塞其他连接,支持同时处理多个客户端的请求。
双向数据通信:客户端可向服务器发送数据(如文本、数值等);
服务器接收后可实时响应(如返回确认信息、处理后的数据),并支持向指定客户端或所有客户端广播消息。
连接状态管理:服务器实时显示已连接的客户端信息(如客户端IP、端口、连接时间),支持主动断开某个客户端连接;客户端也能显示与服务器的连接状态。
异常处理:包含连接超时、客户端异常断开、网络错误等场景的处理逻辑,确保服务器稳定运行。
总的来说,该例程的核心价值是展示CVI中TCP多连接处理和线程并发编程的最佳实践,代码中包含了服务器监听、客户端连接、多线程数据收发、连接管理等关键逻辑,适合作为开发多客户端通信系统的参考模板。

该项目在我笔记本上的完整路径是C:\Users\Public\Documents\National Instruments\CVI2010\samples\tcp\MultiClientServer.cws。下面是通过CVI的起始页面,搜索原厂例程的步骤。

刚才试通了一主多从的TCP通信的例程,没有参考文档就纯粹靠瞎蒙了。这里需要开三个CVI,分别打开MultiClientServer.cws、和两个client.prj。

老规矩,先运行server即MultiClientServer.cws。初始界面这样的,很多控件都是失活的,等待client上线:

然后在默认的debug模式下运行第一个client.prj,显然server这边侦听到有一个client上线了,客户端名称列表框就多了一行记录,同时还会弹出一个窗口Message from Client出来:

然后手动修改成release模式运行第二个client.prj,可见server这边就一共侦听到两个client上线,客户端名称列表框就有了两行记录。同时再弹出一个窗口Message from Client。这里手动把两个client界面和两个Message from Client弹窗都摆好位置:

然后用户就可以尝试双边通信了:

所以我上午的设想的,一个Server.exe配合4个ATE.exe去控制一台4通道OpticaslSuit,应是完全可行的了?

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/5 12:17:07

cursor-free-vip终极指南:一键突破AI工具限制的完整方案

cursor-free-vip终极指南&#xff1a;一键突破AI工具限制的完整方案 【免费下载链接】cursor-free-vip [Support 0.45]&#xff08;Multi Language 多语言&#xff09;自动注册 Cursor Ai &#xff0c;自动重置机器ID &#xff0c; 免费升级使用Pro 功能: Youve reached your t…

作者头像 李华
网站建设 2026/2/6 2:34:27

MTK设备启动保护机制绕过实用教程:高效解锁工具深度解析

MTK-bypass/bypass_utility是一款专为MediaTek芯片设备设计的开源解锁工具&#xff0c;能够有效禁用设备启动时的启动保护机制。通过这款工具&#xff0c;用户可以为后续的系统调试、刷机操作和开发工作提供便利。 【免费下载链接】bypass_utility 项目地址: https://gitcod…

作者头像 李华
网站建设 2026/2/6 1:40:09

20、毫米波(mmWave)介质访问控制综述

毫米波(mmWave)介质访问控制综述 1. 引言 在无线和计算网络中,介质访问控制(MAC)的基本作用之一是“冲突和干扰管理”。像载波侦听多址接入/冲突避免(CSMA/CA)就是无线网络中著名且成功的随机接入方案,它通过避免冲突的概念来协调无线介质访问。 然而,在毫米波(mm…

作者头像 李华
网站建设 2026/2/4 11:21:43

42、LINQ查询表达式与.NET集合类型详解

LINQ查询表达式与.NET集合类型详解 1. 查询表达式介绍 查询表达式是一种强大的工具,它为开发者提供了一种类似于SQL的语法来处理集合数据。在查询表达式中, select 子句可以定义匿名类型。例如,它可以将 IGrouping<TKey, TElement>.Key 重命名为 IsContextualK…

作者头像 李华
网站建设 2026/2/7 23:40:06

vue+springboot社区外来务工人员管理系统_数据分析可视化大屏系统10vz9c0a_jz119

目录已开发项目效果实现截图开发技术介绍系统开发工具&#xff1a;核心代码参考示例1.建立用户稀疏矩阵&#xff0c;用于用户相似度计算【相似度矩阵】2.计算目标用户与其他用户的相似度系统测试总结源码文档获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&…

作者头像 李华
网站建设 2026/2/7 22:39:35

53、多线程编程中的同步、存储、定时器与异步编程模型解析

多线程编程中的同步、存储、定时器与异步编程模型解析 在多线程编程中,数据的处理和线程的管理是关键问题。下面将详细介绍线程本地存储、定时器以及异步编程模型的相关知识和应用。 线程本地存储 在某些情况下,使用同步锁会导致性能和可扩展性受限,或者为特定数据元素提供…

作者头像 李华