Linux/Ubuntu下多机间基于socket通信进行数据交互及C++代码实现

这篇具有很好参考价值的文章主要介绍了Linux/Ubuntu下多机间基于socket通信进行数据交互及C++代码实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、测试说明

  1. 项目需要两台主机(视觉端Nvidia AGX Xavier;控制端Intel NUC10i7)进行机器人位姿、关节指令等double数据传输,计划使用socket通信实现;
  2. 两台主机通过一条网线建立局域网,分别创建新的有线连接:
    服务器端:ipv4:192.168.56.3;子网掩码:255.255.255.0;网关:192.168.56.1
    客户端:ipv4:192.168.56.2;子网掩码:255.255.255.0;网关:192.168.56.1
  3. 服务器端先启动,后启动客户端;
  4. 一定要长时间测试双方通信过程中的收发延时以及数据丢失情况;

二、数据传输实时性及稳定性提升方案

  1. 巨帧(jumbo frame)
# MTU(最大传输单元)的缺省值为1500,通过下面命令将其改为9000
# 每次开机都要重新设置,可设置开机自启动脚本
ifconfig eth0 mtu 9000

经测试,mtu默认保持1500时,发送端发送10000次数据,接收端只能收到300左右。将mtu改为9000后基本消除这个问题。

  1. 更改双方收发缓冲区大小

缓冲区大小计算公式:链接带宽(link_bandwidth)* 往返时间(RTT)/ 8;
例如,如果应用程序是通过一个 100Mbps 的局域网进行通信,其 RRT 为 50 ms,那么缓冲区就是:100 MBps * 0.050 sec / 8 = 0.625 MB = 625 KB

在代码中设置缓冲区大小时,需要转换量级:625 KB * 1024 = 640,000 Byte
实际测试发现,计算出的缓冲区大小往往只有几十KB(详见代码附录)文章来源地址https://www.toymoban.com/news/detail-432791.html

# 查询链接带宽,打印结果中有一项关于speed的信息即为带宽
sudo apt install ethtool
ethtool 网卡名称
# 往返时间RRT查询方法
ping ip地址
  1. 设置双方缓冲区大小
int ret, sock, sock_buf_size;

sock = socket( AF_INET, SOCK_STREAM, 0 );

sock_buf_size = BDP;

ret = setsockopt( sock, SOL_SOCKET, SO_SNDBUF,
                   (char *)&sock_buf_size, sizeof(sock_buf_size) );

ret = setsockopt( sock, SOL_SOCKET, SO_RCVBUF,
                   (char *)&sock_buf_size, sizeof(sock_buf_size) );

三、C++代码

  1. 服务器端:
/*
 * @Author: XUYANG
 * @Date: 2022-02-18 15:07:04
 * @LastEditTime: 2022-02-18 17:59:15
 * @LastEditors: XUYANG
 * @Description:
 * @FilePath: \src\auto_charging_system\robot_planner\src\socket_proc.cpp
 */
//#include <robot_planner/socket_proc.h>
#include <iostream>
#include <vector>
#include <string.h>
#include <thread>
#include <chrono>
#include <sstream>
#include <stdio.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <fstream>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/time.h>
#include <math.h>
#include <iomanip>

#include <sys/types.h> 
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>

using std::cout;
using std::endl;
using std::shared_ptr;
using std::string;
using std::vector;
using namespace std;
using namespace std::chrono;
using std::perror;

#define _MYPORT_ROBOT_ 9054   // 9054
#define _BACKLOG_ROBOT_ 12
#define _BUFFER_SIZE_ 2048    // 70  1024

class NetRobot
{
public:
	NetRobot();
	~NetRobot();
	void mainLoop();
	int socketRecvRun();
	// int socketSendRun();
	int socketSendRun(vector<double> &commands, int flag);
	bool isConnectionOK();
	void parseCommand();
	int initSocketServer();
	bool waitForConnection();


	vector<double> joint_positions = vector<double>(6, 0.0);
	vector<double> joint_speeds = vector<double>(6, 0.0);
	vector<double> joint_currents = vector<double>(6, 0.0);
	vector<double> end_effector_pose = vector<double>(6, 0.0);
	bool is_robotInit_ok_ = false;
	struct timeval tv;
	int recv_counts = 0;
	int send_counts = 0;
	ofstream outfile1;

	bool data_flag = true;

	/* 在sock_fd上进行监听,new_fd 接受新的连接 */
	int sock_fd_, new_fd_;

	/* 自己的地址信息 */
	struct sockaddr_in my_addr_;

	/* 连接者的地址信息*/
	struct sockaddr_in their_addr_;

	int sin_size_;
	/* 从buffer中读取的位数 */

	int buf_bytes_;
	/* buffer */

	char buf_[_BUFFER_SIZE_];
	char buf_send_[_BUFFER_SIZE_];

	bool is_connection_ok_;

};

NetRobot::NetRobot()
{
	sin_size_ = sizeof(struct sockaddr_in);
	/*
		create ......
	*/
}

NetRobot::~NetRobot()
{
	outfile1.close();
	/*
		delete ......
	*/
}

int NetRobot::initSocketServer()
{
	outfile1 = ofstream("/home/vision/Documents/socket_data/server_data_01.txt", ios::trunc);
	/* 如果调用 socket() 出错,则退出 */
	if ((sock_fd_ = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		/* 输出错误提示并退出 */
		perror(" socket_robot");
		return -1;
	}

#if 1
	// 设置缓冲区大小
	int socket_buf_size = 8192; // 16 KB:16384; 8 KB: 8192
	setsockopt(sock_fd_, SOL_SOCKET, SO_SNDBUF, (char *)&socket_buf_size, sizeof(socket_buf_size));
	setsockopt(sock_fd_, SOL_SOCKET, SO_RCVBUF, (char *)&socket_buf_size, sizeof(socket_buf_size));

#endif /*


#if 0
	// 禁用nagle算法,最小化报文传输延时
	int flag = 1;
	if ( setsockopt(sock_fd_, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag)) == -1 )
	{
		cout << "couldn't setsockopt(TCP_NODELAY)" << endl;
		return -1;
	}

#endif /*


	/* 主机字节顺序 */
	my_addr_.sin_family = AF_INET;
	/* 网络字节顺序,短整型 */
	my_addr_.sin_port = htons(_MYPORT_ROBOT_); // 9054
	/* 将运行程序机器的IP填充入s_addr */
	my_addr_.sin_addr.s_addr = INADDR_ANY; //  INADDR_ANY  0.0.0.0 monitor all
	/* 将此结构的其余空间清零 */
	bzero(&(my_addr_.sin_zero), 8);
	/* 这里是我们一直强调的错误检查!! */
	int iSockOptVal = 1;
	/* 检测是否端口备占用 */
	if (setsockopt(sock_fd_, SOL_SOCKET, SO_REUSEADDR, &iSockOptVal, sizeof(iSockOptVal)) == -1)
	{
		perror("setsockopt fail");
		close(sock_fd_);
		return -1;
	}
	if (bind(sock_fd_, (struct sockaddr *)&my_addr_, sizeof(struct sockaddr)) == -1)
	{
		/* 如果调用bind()失败,则给出错误提示,退出 */
		perror(" bind_robot ");
		return -1;
	}
	/* 这里是我们一直强调的错误检查!! */
	if (listen(sock_fd_, _BACKLOG_ROBOT_) == -1)
	{
		/* 如果调用 listen 失败,则给出错误提示,退出 */
		perror("listen_robot");
		return -1;
	}
	// ROS_INFO("Socket server initialized");
	cout << "Socket server initialized" << endl;
	return 0;
}

/* 等待Socket客户端连接,连接成功返回true;失败返回false*/
bool NetRobot::waitForConnection()
{
	/* 接收新的连接,若无连接请求,则线程睡眠等待连接请求 */
	// ROS_INFO("Waiting for new connection");
	cout << "Waiting for new connection" << endl;
	new_fd_ = accept(sock_fd_, (struct sockaddr *)&their_addr_, (socklen_t *)&sin_size_);

	/* 若accept返回为-1,则连接错误,重新等待连接 */
	if (new_fd_ < 0)
	{
		perror(" accept_robot ");
		return false;
	}
	else
	{
		char *ip = inet_ntoa(their_addr_.sin_addr);

		// ROS_INFO("Client@%s connected\n", ip);
		cout << "Client@" << ip << " connected!" << endl;
#if 1
		/* 用非阻塞方式 */
		fcntl(new_fd_, F_SETFL, O_NONBLOCK);
		/* for send/receive map */
#endif
		return true;
	}
}

bool NetRobot::isConnectionOK()
{
	if (initSocketServer())					 // 初始化socket,监听连接请求
		return false;						 // 初始化有问题
	is_connection_ok_ = waitForConnection(); // 等待连接请求
	close(sock_fd_);						 // 建立连接后,关闭监听socket
	return is_connection_ok_;				 // 初始化过程已完成
}

// 对buf_接收到的指令进行解析
void NetRobot::parseCommand()
{
	if(data_flag == false)
	{
		data_flag = true;
		return;
	}
    // *(double* )(buf_+8*i) 
	cout << "!!! recv_counts: " << recv_counts << endl;
	cout << *(double* )buf_ << endl;

	// if (buf_[0] == 'A') // 解析1:依次返回每个关节的位置(°)、速度(m/s)、电流值(A)
	if (fabs(*(double* )buf_ - 1111.1111) < 1e-4)
	{
		// 前8字节:标志位; 9-56字节:1-6关节角度值;
		double *pPosition = (double *)(buf_ + 8);
		for (int i = 0; i < 6; i++) // 将位置信息存入指定容器中
		{
			joint_positions[i] = pPosition[i];
		}
		cout << "yyds..." << endl;
		outfile1 << recv_counts << " " << joint_positions[0] << " " << joint_positions[1] << " "
		         << joint_positions[2] << " " << joint_positions[3] << " "  
				 << joint_positions[4] << " " << joint_positions[5] << endl;
	}
	else if (fabs(*(double* )buf_ - 2222.2222) < 1e-4)
	{
		// 前8字节:标志位; 9-56字节:1-6关节速度值;
		double *pSpeed = (double *)(buf_ + 8);
		for (int i = 0; i < 6; i++) // 将速度信息存入指定容器中
		{
			joint_speeds[i] = pSpeed[i];
		}
		cout << "yyds..." << endl;
		outfile1 << recv_counts << " " << joint_speeds[0] << " " << joint_speeds[1] << " "
		         << joint_speeds[2] << " " << joint_speeds[3] << " "  
				 << joint_speeds[4] << " " << joint_speeds[5] << endl;
	}
	else if (fabs(*(double* )buf_ - 3333.3333) < 1e-4)
	{

		// double *pCurrent = (double *)(buf_);
		// joint_currents[0] = pCurrent[0];
		// cout << "yyds..." << endl;
		// outfile1 << recv_counts << " " << joint_currents[0] << endl;
#if 1
		// // 前8字节:标志位; 9-56字节:1-6关节电流值
		double *pCurrent = (double *)(buf_ + 8);
		for (int i = 0; i < 6; i++)   // 将电流信息存入指定容器中
		{
			joint_currents[i] = pCurrent[i];
		}

		// cout << "yyds..." << endl;
		outfile1 << recv_counts << " " << joint_currents[0] << " " << joint_currents[1] << " "
		         << joint_currents[2] << " " << joint_currents[3] << " "  
				 << joint_currents[4] << " " << joint_currents[5] << endl;

		// for (int i = 0; i < 6; i++)
		// {
		// 	cout << setiosflags(ios::fixed) << setprecision(6) << joint_currents[i] << " ";
		// }
		// cout << endl;
#endif
	}
	// else if (buf_[0] == 'B')  // 解析2:初始状态下机械臂已就位,告诉视觉端,机械臂已就位
	else if (fabs(*(double* )buf_ - 4444.4444) < 1e-4)
	{
		is_robotInit_ok_ = true;
	}
	// else if (buf_[0] == 'C')  // 解析3:返回机械臂末端位姿:平移分量,旋转分量
	else if (fabs(*(double* )buf_ - 5555.5555) < 1e-4)
	{
		//
		double *pEEpose = (double *)(buf_ + 8);
		for (int i = 0; i < 6; i++) // 将末端位姿信息存入指定容器中
		{
			end_effector_pose[i] = pEEpose[i];
		}
		// for (int i = 0; i < 6; i++)
		// {
		// 	cout << end_effector_pose[i] << " ";
		// }
		// cout << endl;
	}

	recv_counts++;
}

int NetRobot::socketRecvRun()
{
	memset(buf_, 0, _BUFFER_SIZE_);

	buf_bytes_ = recv(new_fd_, buf_, _BUFFER_SIZE_, 0);
	// cout << "!!! " << buf_bytes_ << endl;
	/* 客户端连接关闭,结束连接,等待新的连接请求 */
	if (buf_bytes_ == 0)
	{
		// gettimeofday(&tv, NULL);
		// printf("millisecond: %ld\n", tv.tv_sec * 1000 + tv.tv_usec / 1000); // 毫秒
		// printf("microsecond: %ld\n", tv.tv_sec * 1000000 + tv.tv_usec); // 徽秒
		
		// ROS_WARN("Socket client has disconnected, close current connection");
		cout << "Socket client has disconnected, close current connection." << endl;
		data_flag = false;
		close(new_fd_);
		is_connection_ok_ = false;
		return 0;
	}
	/* 接收异常,结束连接,等待新的连接请求 */
	if (buf_bytes_ < 0)
	{
		if (errno == EWOULDBLOCK)
		{
			data_flag = false;
			// 内核缓冲区没有数据了
			cout << "there is no data available now." << endl;
			outfile1 << "111111" << endl;
		}
		else if (errno == EINTR)
		{
			data_flag = false;
			// 被信号中断了,需要重新尝试发送
			cout << "recv data interrupted by signal." << endl;
			outfile1 << "222222" << endl;
		}
		else
		{
			// 出现了严重错误
			cout << "Socket receiving error, close current connection." << endl;
			data_flag = false;
			close(new_fd_);
			is_connection_ok_ = false;
			return 0;
		}
	}
	/* 接收正常,将buffer最后一位的\n改成\0 */
	if (buf_bytes_ > 0)
	{
		// 视情况判断这部分是否保留
#if 0
		if (buf_[buf_bytes_ - 1] == '\n')
		{
			buf_[buf_bytes_ - 1] = '\0';
			buf_bytes_--;
		}
#endif

		// cout << "Received data: "; 
		// for (int i = 0; i < 6; i++)
		// {
		// 	cout << *(double* )(buf_+8*i) << " ";
		// }
		// cout << endl;
	}

	return 1;
}

int NetRobot::socketSendRun(vector<double> &commands, int flag)
{
	// 要发送什么东西,先存在buf_send_中!
	memset(buf_send_, 0, _BUFFER_SIZE_);

	// double *pData = (double *)(buf_send_ + 8);
	double *pData = (double *)buf_send_;

	if (flag == 0)        // 指令1:末端期望位姿; 旋转分量用四元数表示还是什么呢?
	{
		pData[0] = 1111.1111;
		for (int i = 0; i < 6; i++)   // 平移+旋转 
		{
			if (i == 0)
			{
				pData[i+1] = send_counts;
				continue;
			}
			pData[i+1] = commands[i];
		}
	}

	int ret = send(new_fd_, buf_send_, _BUFFER_SIZE_, 0);

	if (ret == -1)
	{
		if (errno == EWOULDBLOCK)
		{
			// 非阻塞模式下send函数由于TCP窗口太小发不出去数据
			cout << "send data error as TCP window size is too small." << endl;
			// 需要判别是否需要发送!!!
			return 0;
		}
		else if (errno == EINTR)
		{
			// 被信号中断
			cout << "sending data interrupted by signal." << endl;
			// 需要判别是否需要发送!!!
			return 0;
		}
		else
		{
			// 出现严重错误!!
			cout << "send data error." << endl;
			close(new_fd_);
			return -1;
		}
	}
	else if (ret == 0)
	{
		// 客户端关闭了连接
		cout << "the client down, send data error." << endl;
		close(new_fd_);
		return -1;
	}
	
	// cout << "send the msg to robot successfully!" << endl;
	cout << "!!! send_counts: " << send_counts << endl;
	send_counts++;
	return 0;
}

int main(int argc, char **argv)
{
	NetRobot* netRobot = new NetRobot;
	if (netRobot->isConnectionOK() == true)
	{
		cout << "connect is success!" << endl;
	}

	// vector<double> commands = {12.0, 12.0, 12.0, 12.0, 12.0, 12.0};
	// vector<double> commands = {0.1, 0.1, 0.1, 0.1, 0.1, 0.1};
	vector<double> commands = {12.3, 12.3, 12.3, 12.3, 12.3, 12.3};
	// vector<double> commands = {123.0, 123.0, 123.0, 123.0, 123.0, 123.0};
	// vector<double> commands = {120, 120, 120, 120, 120, 120};

	while (1)
	{
		// 接受
		netRobot->socketRecvRun();
		netRobot->parseCommand();

		// 发送
		netRobot->socketSendRun(commands, 0);

		usleep(1000);  // 微秒
	}

	// netRobot->socketRecvRun();
	// netRobot->parseCommand();

	// // 发送
	// netRobot->socketSendRun(commands, 0);
	// close(netRobot->new_fd_);

	return 0;
}
  1. 客户端

#include <iostream>
#include <vector>
#include <string.h>
#include <thread>
#include <chrono>
#include <sstream>
#include <stdio.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <fstream>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/time.h>
#include <math.h>
#include <iomanip>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>

using std::cout;
using std::endl;
// using std::shared_ptr;
using std::string;
using std::vector;
using namespace std;
// using namespace std::chrono;
using std::perror;

// #define _SERVER_ADDRESS_ "127.0.0.1"
#define _SERVER_ADDRESS_ "192.168.56.3"
#define _SERVER_PORT_ 9054   // 9054
#define _BUFFER_SIZE_ 2048   // 70  1024

class NetClient
{
public:
	NetClient();
	~NetClient();
	void mainLoop();
	int socketRecvRun();
	// int socketSendRun();
	int socketSendRun(vector<double> &commands, int flag);
	bool isConnectionOK();
	int initSocketClient();
	bool tryToConnection();
	void parseCommand();

	vector<double> eepose_cmd = vector<double>(6, 0.0);

	bool is_robotInit_ok_ = false;
	struct timeval tv;
	int recv_counts = 0;
	int send_counts = 0;
	ofstream outfile1;
	bool data_flag = true;

	/* 在sock_fd上进行监听,new_fd 接受新的连接 */
	int sock_fd_, new_fd_;

	/* 自己的地址信息 */
	struct sockaddr_in my_addr_;

	/* 连接者的地址信息*/
	struct sockaddr_in their_addr_;

	int sin_size_;
	/* 从buffer中读取的位数 */

	int buf_bytes_;
	/* buffer */

	char buf_[_BUFFER_SIZE_];
	char buf_send_[_BUFFER_SIZE_];
	char buf_xy_[_BUFFER_SIZE_];

	bool is_connection_ok_;

};

NetClient::NetClient()
{
	// sin_size_ = sizeof(struct sockaddr_in);
	/*
		create ......
	*/
}
NetClient::~NetClient()
{
	// outfile1.close();
	/*
		delete ......
	*/
}

int NetClient::initSocketClient()
{
	// outfile1 = ofstream("/home/vision/Documents/socket_data/client_data_01.txt", ios::trunc);
	// 1.创建一个socket
	sock_fd_ = socket(AF_INET, SOCK_STREAM, 0);
	if (sock_fd_ == -1)
	{
		std::cout << "create client socket error." << std::endl;
		return -1;
	}

#if 1

	int socket_buf_size = 8192;  // 16KB:16384; 8KB:8192 
	setsockopt(sock_fd_, SOL_SOCKET, SO_SNDBUF, (char *)&socket_buf_size, sizeof(socket_buf_size));
	setsockopt(sock_fd_, SOL_SOCKET, SO_RCVBUF, (char *)&socket_buf_size, sizeof(socket_buf_size));

#endif



#if 0

	int flag = 1;
	if ( setsockopt(sock_fd_, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag)) == -1 )
	{
		cout << "couldn't setsockopt(TCP_NODELAY)" << endl;
		return -1;
	}
	

#endif

	// 2.连接服务器
	// ROS_INFO("Try to connect server.");
	cout << "Try to connect server." << endl;
	my_addr_.sin_family = AF_INET;
	my_addr_.sin_addr.s_addr = inet_addr(_SERVER_ADDRESS_);
	my_addr_.sin_port = htons(_SERVER_PORT_);
	if (connect(sock_fd_, (struct sockaddr *)&my_addr_, sizeof(my_addr_)) == -1)
	{
		std::cout << "connect socket error." << std::endl;
		close(sock_fd_);
		return -1;
	}
	// ROS_INFO("Socket client initialized.");
	cout << "Socket client initialized." << endl;
	return 0;
}

bool NetClient::isConnectionOK()
{
	if (initSocketClient())				   // 初始化socket,监听连接请求
		return false;					   // 初始化有问题
	is_connection_ok_ = tryToConnection(); // 等待连接请求
	// close(sock_fd_);					   // 建立连接后,关闭监听socket
	return is_connection_ok_;			   // 初始化过程已完成
}

bool NetClient::tryToConnection()
{
	//连接成功以后,我们再将 sock_fd_ 设置成非阻塞模式,
	//不能在创建时就设置,这样会影响到 connect 函数的行为
#if 1
	int oldSocketFlag = fcntl(sock_fd_, F_GETFL, 0);
	int newSocketFlag = oldSocketFlag | O_NONBLOCK;
	if (fcntl(sock_fd_, F_SETFL, newSocketFlag) == -1)
	{
		close(sock_fd_);
		std::cout << "set socket to nonblock error." << std::endl;
		return false;
	}
#endif

	return true;
}

// 对buf_接收到的指令进行解析
void NetClient::parseCommand()
{
	if (data_flag == false)
	{
		data_flag = true;
		return;
	}

	// cout << "!!! recv_counts: " << recv_counts << endl;
	// cout << *(double* )buf_ << endl;

	// if (buf_[0] == 'A')      // 解析1:末端位姿指令   平移量+旋转量   旋转量用四元数还是什么表示呢?
	if (fabs(*(double* )buf_ - 1111.1111) < 1e-4)
	{
		double *pPose = (double *)(buf_ + 8);
		for (int i = 0; i < 6; i++) 
		{
			eepose_cmd[i] = pPose[i];
		}

		// cout << "yyds..." << endl;
		// outfile1 << recv_counts << " " << eepose_cmd[0] << " " << eepose_cmd[1] << " "
		//          << eepose_cmd[2] << " " << eepose_cmd[3] << " "  
		// 		 << eepose_cmd[4] << " " << eepose_cmd[5] << endl;

		// for (int i = 0; i < 6; i++)
		// {
		// 	cout << eepose_cmd[i] << " ";
		// }
		// cout << endl;

	}


	recv_counts++;
}

int NetClient::socketRecvRun()
{
	memset(buf_, 0, _BUFFER_SIZE_);

	buf_bytes_ = recv(sock_fd_, buf_, _BUFFER_SIZE_, 0);
	/* 客户端连接关闭,结束连接,等待新的连接请求 */
	if (buf_bytes_ == 0)
	{
		// ROS_WARN("Socket server has disconnected, close current connection.");
		std::cout << "Socket server has disconnected, close current connection." << std::endl;
		data_flag = false;
		close(sock_fd_);
		is_connection_ok_ = false;
		return 0;
	}
	/* 接收异常,结束连接,等待新的连接请求 */
	if (buf_bytes_ < 0)
	{
		if (errno == EWOULDBLOCK)
		{
			data_flag = false;
			// 内核缓冲区没有数据了
			// cout << "there is no data available now." << endl;
			// outfile1 << "111111" << endl;
		}
		else if (errno == EINTR)
		{
			data_flag = false;
			// 被信号中断了,需要重新尝试发送
			// cout << "recv data interrupted by signal." << endl;
			// outfile1 << "222222" << endl;
		}
		else
		{
			// 出现了严重错误
			// cout << "Socket receiving error, close current connection." << endl;
			data_flag = false;
			close(sock_fd_);
			is_connection_ok_ = false;
			return 0;
		}

	}
	/* 接收正常,将buffer最后一位的\n改成\0 */
	if (buf_bytes_ > 0)
	{
		// 视情况判断这部分是否保留
#if 0
		if (buf_[buf_bytes_ - 1] == '\n')
		{
			buf_[buf_bytes_ - 1] = '\0';
			buf_bytes_--;
		}
#endif
		// ROS_INFO("Received command: %s\n", buf_);

		// cout << "Received data: "; 
		// for (int i = 0; i < 6; i++)
		// {
		// 	cout << *(double* )(buf_+8*i) << " ";
		// }
		// cout << endl;
	}

	return 1;
}

int NetClient::socketSendRun(vector<double> &commands, int flag)
{
	// 要发送什么东西,先存在buf_send_中!
	memset(buf_send_, 0, _BUFFER_SIZE_);

	// double *pData = (double *)(buf_send_ + 8);
	double *pData = (double *)buf_send_;

	if (flag == 0)           // 指令1:所有关节位置
	{
		pData[0] = 1111.1111;          // 前8字节:标志位
		for (int i = 0; i < 6; i++)    // 9-56字节:1-6关节角度值;
		{
			pData[i+1] = commands[i];
		}
	}
	else if (flag == 1)       // 指令2:所有关节速度
	{
		pData[0] = 2222.2222;          // 前8字节:标志位
		for (int i = 0; i < 6; i++)    // 9-56字节:1-6关节速度值;
		{
			pData[i+1] = commands[i];
		}
	}
	else if (flag == 2)       // 指令3:所有关节电流
	{
		// for (int i = 0; i < 6; i++)
		// {
		// 	cout << setiosflags(ios::fixed) << setprecision(6) << commands[i] << " ";
		// }
		// cout << endl;

		pData[0] = 3333.3333;          // 前8字节:标志位
		for (int i = 0; i < 6; i++)    // 9-56字节:1-6关节电流值;
		{
			// if (i == 0)
			// {
			// 	pData[i+1] = send_counts;
			// 	continue;
			// }
			pData[i+1] = commands[i]; 
		}
	}
	else if (flag == 3)      // 指令4:机械臂已就位
	{
		pData[0] = 4444.4444;
	}
	else if (flag == 4)      // 指令5:末端位姿:平移+旋转  旋转量用四元数还是什么呢
	{
		pData[0] = 5555.5555;
		for (int i = 0; i < 6; i++)   // 平移+旋转
		{
			pData[i+1] = commands[i];
		}
	}

	// cout << strlen(buf_send_) << endl;
	// int ret = send(sock_fd_, buf_send_, strlen(buf_send_), 0);

	// gettimeofday(&tv, NULL);
	// printf("millisecond: %ld\n", tv.tv_sec * 1000 + tv.tv_usec / 1000); // 毫秒
	// printf("microsecond: %ld\n", tv.tv_sec * 1000000 + tv.tv_usec); // 徽秒

	int ret = send(sock_fd_, buf_send_, _BUFFER_SIZE_, 0);
	if (ret == -1)
	{
		if (errno == EWOULDBLOCK)
		{
			// 非阻塞模式下send函数由于TCP窗口太小发不出去数据
			// cout << "send data error as TCP window size is too small." << endl;
			// 需要判别是否需要发送!!!
			return 0;
		}
		else if (errno == EINTR)
		{
			// 被信号中断
			// cout << "sending data interrupted by signal." << endl;
			// 需要判别是否需要发送!!!
			return 0;
		}
		else
		{
			// gettimeofday(&tv, NULL);
			// printf("millisecond: %ld\n", tv.tv_sec * 1000 + tv.tv_usec / 1000); // 毫秒
			// printf("microsecond: %ld\n", tv.tv_sec * 1000000 + tv.tv_usec); // 徽秒
			// cout << "errno: " << errno << endl;
			// 出现严重错误!!
			// cout << "send data error." << endl;
			close(sock_fd_);
			return -1;
		}
	}
	else if (ret == 0)
	{
		// 客户端关闭了连接
		// cout << "the server down, send data error." << endl;
		close(sock_fd_);
		return -1;
	}

	// cout << "send the msg to server successfully!" << endl;
	// cout << "!!! send_counts: " << send_counts << endl;
	send_counts++;
	return 0;
}

int main(int argc, char *argv[])
{
	NetClient* netClient = new NetClient;
	if (netClient->isConnectionOK() == true)
	{
		cout << "connect is success!" << endl;
	}
	
	vector<double> eepose = {123.4056, 0.0012, 5.0321, 25.06397, 6.08924, 0.0030};

	// vector<double> commands = {123, 123.0, 123.0, 123.0, 123.0, 123.0};

	while (1)
	{
		// 接受
		netClient->socketRecvRun();
		netClient->parseCommand();

		// 发送
		netClient->socketSendRun(eepose, 4);
		usleep(1000);  // 微秒
	}

	// gettimeofday(&netClient->tv, NULL);
	// printf("millisecond: %ld\n", netClient->tv.tv_sec * 1000 + netClient->tv.tv_usec / 1000); // 毫秒
	// printf("microsecond: %ld\n", netClient->tv.tv_sec * 1000000 + netClient->tv.tv_usec); // 徽秒

	// netClient->socketSendRun(joint_current, 2);

	// netClient->socketRecvRun();
	// netClient->parseCommand();

	// gettimeofday(&netClient->tv, NULL);
	// printf("millisecond: %ld\n", netClient->tv.tv_sec * 1000 + netClient->tv.tv_usec / 1000); // 毫秒
	// printf("microsecond: %ld\n", netClient->tv.tv_sec * 1000000 + netClient->tv.tv_usec); // 徽秒

	// close(netClient->sock_fd_);

	return 0;
}

到了这里,关于Linux/Ubuntu下多机间基于socket通信进行数据交互及C++代码实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • MacOS使用USB接口与IPhone进行Socket通信

    演示效果如下:   开源地址: GitHub - rsms/peertalk: iOS and Mac Cocoa library for communicating over USB   克隆源码: 克隆后打开peertalk然后启动xcode工程  先启动MacOS服务端工程,再启动iOS客户端工程    客户端 服务端          

    2024年02月17日
    浏览(32)
  • Linux——socket网络通信

    Socket套接字 由远景研究规划局(Advanced Research Projects Agency, ARPA)资助加里福尼亚大学伯克利分校的一个研究组研发。其目的是将 TCP/IP 协议相关软件移植到UNIX类系统中。设计者开发了一个接口,以便应用程序能简单地调用该接口通信。这个接口不断完善,最终形成了 Socket套

    2024年02月11日
    浏览(32)
  • Linux系统编程,socket通信编程。

    管道,共享内存,消息队列。 跨机器通信,在网络上传递数据,通过socket套接字来实现。 头文件,#include sys/types.h,#include sys/socket.h int socket(int domain, int type, int protocol); domain,协议族,type。类型,protocol,使用的特定的协议 返回值,0,成功,-1,失败, 在一个监听socket上接

    2024年02月07日
    浏览(33)
  • 远程服务和web服务和前端,三方通过socket和websocket进行双向通信传输数据

    1. 什么是socket? 在计算机通信领域,socket 被翻译为“套接字”,它是计算机之间进行通信的一种约定或一种方式。通过 socket 这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据。 2. 什么是websocket? WebSocket是一种网络通信协议,是HTML5新增的特性,

    2024年02月15日
    浏览(40)
  • 14.11 Socket 基于时间加密通信

    在之前的代码中我们并没有对套接字进行加密,在未加密状态下我们所有的通信内容都是明文传输的,这种方式在学习时可以使用但在真正的开发环境中必须要对数据包进行加密,此处笔者将演示一种基于时间的加密方法,该加密方法的优势是数据包每次发送均不一致,但数

    2024年02月08日
    浏览(67)
  • 基于 Socket 接口实现自定义协议通信

    访问【WRITE-BUG数字空间】_[内附完整源码和文档] 根据自定义的协议规范,使用 Socket 编程接口编写基本的网络应用软件。 掌握 C 语言形式的 Socket 编程接口用法,能够正确发送和接收网络数据包 开发一个客户端,实现人机交互界面和与服务器的通信 开发一个服务端,实现并

    2024年02月06日
    浏览(26)
  • 1、Linux中的socket与TCP通信

    1、所谓 socket(套接字),就是 对网络中不同主机上的应用进程之间进行双向通信的端点的抽象 。 2、一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络

    2023年04月08日
    浏览(28)
  • 基于python的socket网络通信【1】

    学习了大佬的知识,简单记一些笔记 https://www.jianshu.com/p/066d99da7cbd http://c.biancheng.net/view/2351.html 在计算机通信领域,socket 被翻译为“套接字”,它是计算机之间进行通信的一种约定或一种方式。通过 socket 这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算

    2024年02月02日
    浏览(28)
  • Ubuntu下多设备映射名称设置

    在机器人开发过程中,开发者会使用到多个外设,在传感器外设中,会用到激光雷达、摄像头等,为了读取到外设数据,首先需要获取到外设名称,Ubuntu系统默认根据外设接入的顺序,定义接口名称。 比如激光雷达首先接入,则激光雷达对应的端口名便为 /dev/ttyUSB0 ,此时后

    2024年01月25日
    浏览(23)
  • MFC Socket和合信CTMC M266ES 运动控制型PLC通信进行数据交换

             1、前两篇文章通过对Snap7和S7-1200/S7-1500PLC的通信进行了详细的介绍。Snap7的优点开源性强、使用方便易于上手,跨平台和可移植性性强。但是Snap7也有个缺点就是只能访问PLC的DB、MB、I、Q区进行数据读写,不能对V区进行读写,有人说可以读写V区,但是目前我还没有得

    2024年02月01日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包