TCP/IP开发实例(C++与LabVIEW的TCP通信 多线程)

该文介绍了如何使用C++作为服务器端,通过WinSock2库实现TCP/IP通信,LabVIEW作为客户端进行指令交互。C++利用多线程提高效率,LabVIEW利用其强大的流数据处理API进行数据显示。配置VSCode时需添加-lws2_32链接库以解决编译错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

TCP/IP开发实例(C++与LabVIEW的TCP通信 多线程)

一、本文目标:

将C++端作为Server,主要用于进行中心数据处理,而Labview作为用户端,主要进行指令的发送以及接受来自服务器的数据进行实时显示。这样做的好处有:

1.Labview对于流数据的梳理有着很多强大的封装好的API,可以进行调用,尤其是用于强度图(二维数组)的显示。

2.Labview是基于图形化变成,对于程序的控制灵活度没有使用代码编程的语言便捷,且C++有着强大的开源社区以及各种数据处理的头文件。

3.使用C++的多线程结构,进一步提高程序效率与灵活度。

二、写在前面:

本案例将使用C++的 WinSock2 进行TCP/IP,通信,且运行的编译环境为VSCode,在导入这个头文件后运行程序会报错,需要读者进行如下操作:打开task.json文件,将“-lws2_32”下如下图红色框所在位置(千万不要写错位置,也不要写在其他行,否则亲测也会报错)
在这里插入图片描述

三、C++代码(作为服务器端)

//code C++
#include <iostream>
#include <WinSock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <thread>
using namespace std;
#pragma comment(lib,"WS2_32.lib")

//定义一些全局变量,便于所有函数调用
char recvBuffer[200] = ""; //接受指令的缓存区,大小根据实际需要开辟,这里为200
char sendBuffer[12500] = "";//发送数据的缓存区,大小根据实际需要开辟,这里为12500
sockaddr_in serverAddr;
sockaddr_in clientAddr;
SOCKET serverSock;
int client;

/*############################################################################
功能:与上位机建立建立TCP连接
############################################################################*/
void buildTcpServer(){
    //初始化Socket
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);
  
    serverSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	serverAddr.sin_port = htons(9999);
	//先绑定
	if (bind(serverSock, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
	{
		printf("127.0.0.1 bind fail!\n");
		return;
	}
	//设置服务器上的socket为监听状态
	if (listen(serverSock, 5) < 0)
	{
		printf("127.0.0.1 listen fail!\n");
		return;
	}
}

/*############################################################################
功能:接受来自上位机的指令
############################################################################*/
void recvCommand()
{
    while (true)
	{
		printf("Listening on port: %d\n", 9999);
		//调用accept函数后,会进入阻塞状态
		//accept返回一个套接字的文件描述符,这样服务器端便有两个套接字的文件描述符,
		//serverSocket和client。
		//serverSocket仍然继续在监听状态,client则负责接收和发送数据
		//clientAddr是一个传出参数,accept返回时,传出客户端的地址和端口号
		//addr_len是一个传入-传出参数,传入的是调用者提供的缓冲区的clientAddr的长度,以避免缓冲区溢出。
		//accept阻塞执行,直到获取到有客户端连接
		int clientAddrLen = sizeof(clientAddr);
        
		client = accept(serverSock, (struct sockaddr*)&clientAddr, &clientAddrLen);
		if (client < 0)
		{
			perror("accept");
			continue;
		}
		printf("\nrecv client data...n");
		//inet_ntoa   ip地址转换函数,将网络字节序IP转换为点分十进制IP
		//表达式:char *inet_ntoa (struct in_addr);
		printf("IP is %s\n", inet_ntoa(clientAddr.sin_addr));
		printf("Port is %d\n", htons(clientAddr.sin_port));
		while (1)
		{
			if (recv(client, recvBuffer, 200, 0) < 0)
			{
				perror("recv");
				continue;
			}			
            
            printf("the data we received is %s \n",recvBuffer);

            //清空接受数据的数组
            recvBuffer[200]={0};
            memset(recvBuffer,'\0',sizeof(recvBuffer));
		}
	}
}

//向上位机发送数据,这里我们一次性发送从0~124一共125个数字
void sendData(){
    while(1){
        for(int i=0;i<125;i++) sendBuffer[i] = i%125;
        send(client, sendBuffer, 125, 0);
    }
}


int main()
{
	buildTcpServer();

    thread sendDataThread(sendData);
    thread recvCommandThread(recvCommand);

    sendDataThread.join();
    recvCommandThread.join();
    sendDataThread.detach();
    recvCommandThread.detach();

    return 0;
}

四、客户端(Labview)

图中有不明白的地方可以留言,要是读者感兴趣可以专门出一期关于Labview的一些操作。其中主要就是通过Channel实现数据的异步非阻塞传输。特别注意这里的IP地址和端口号一定要和C++C中设置的已知且没有被其他程序占用。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值