C++ - TCP网络传输如何发送结构体类型
示例1、tcp网络传输如何发送结构体类型
在C++中,要通过TCP网络传输结构体类型,你需要将结构体序列化为字节流,然后在另一端反序列化。这里有一个简单的例子:
#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
// 假设的结构体
struct MyStruct {
int id;
float value;
// 序列化函数
char* serialize() const {
char* buffer = new char[sizeof(MyStruct)];
memcpy(buffer, &this->id, sizeof(int));
memcpy(buffer + sizeof(int), &this->value, sizeof(float));
return buffer;
}
// 反序列化函数
void deserialize(char* buffer) {
memcpy(&this->id, buffer, sizeof(int));
memcpy(&this->value, buffer + sizeof(int), sizeof(float));
}
};
int main() {
int sockfd;
struct sockaddr_in servaddr;
// 创建socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
// 服务器地址
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(1234);
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
// 连接服务器
connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
// 创建结构体实例
MyStruct obj = {123, 3.14f};
// 序列化并发送
char* buffer = obj.serialize();
send(sockfd, buffer, sizeof(MyStruct), 0);
delete[] buffer;
// 接收并反序列化
char recvBuffer[sizeof(MyStruct)];
recv(sockfd, recvBuffer, sizeof(recvBuffer), 0);
MyStruct receivedObj;
receivedObj.deserialize(recvBuffer);
// 输出接收到的结构体成员
std::cout << "Received ID: " << receivedObj.id << ", Value: " << receivedObj.value << std::endl;
// 关闭socket连接
close(sockfd);
return 0;
}
在这个例子中,MyStruct
结构体包含了两个成员:id
和 value
。serialize
函数将结构体转换为字节流,而 deserialize
函数从字节流中恢复结构体。
在实际的TCP通信过程中,你需要确保发送和接收方的序列化和反序列化方式完全一致,以正确地重建结构体数据。
示例2、TCP-socket发送结构体类型数据
UDP传输模式是数据报,TCP传输模式为字节流,字节流与数据报区别在于有边界与无边界。例如:TCP客户端发送了三个数据包,开的缓存足够大服务端一次可接收三个数据包的数据,这就是无边界。UDP客户端发送了三个数据包,就算开的缓存足够大服务端一次也只能接收一个数据包,这就是有边界。
还有就是协议会维护源地址和目的地址直到协议要求断开连接,这就决定了TCP不能进行广播和多播。
如何使用TCP发送结构体类型数据:
//使用结构体转换成字符串发送,在服务器端直接转为结构体
char send_buf[1024] = "tony 2000";
memset(send_buf, 0, 1024);//初始化为0
struct msg
{
int cmd;
int sendID;
int recvID;
string name;
int number;
};
//初始化结构体数据
msg msg1;
msg1.cmd = COMMAND;
msg1.sendID = 2120100324;
msg1.recvID = 2120100325;
msg1.name = "Tony";
msg1.number = 2000;
//以字符串形式发送,因为TCP/IP是字节流通信
//第一种方法:
memcpy(send_buf,&msg1,sizeof(msg));
int len_send = send(Socket,send_buf,sizeof(send_buf),0);
//第二种方法:
int len_send = send(Socket,(char *)&msg1,sizeof(msg),0);
如上所示:
TCP是无边界的字节流传输,所以需要将结构体转换为字符串后在发送,最后三行用了两种方法发送属于结构体类型的数据,通过TCP传输。最后在接收方需要转换为结构体。
代码片段解释:
第一种方法:数组属于字符串,该方法是将要发送结构体所占字节大小考到数组中,再通过数组发送。
第二种方法:将该结构体地址转化为char* 类型的地址,目的是使该指针加1移动时 是按一个字节移动,而不是加1按该结构体大小移动,然后发送该结构 体所占字节大小。
示例3、C++ socket 传输不同类型的数据
1.1 使用结构体
注意:(发送方和接收方都需要定义相同的结构体)
struct Student
{
int iId;
string strName;
bool bSex; //为了节省内存空间,性别采用一个字节的BOOL类型表示
};
II.发送方代码(客户端)
struct Student stu; //声明一个Student结构体变量
stu.iId = 1001;
stu.bSex = true; //true表示男性,false表示女性,你反过来也行,别打拳
stu.strName = "abcdefzzzzz";
//下面的m_sclient是客户端(发送方)的Socket套接字
//方法一:推荐如下
send(m_sclient, (char*)&stu, sizeof(Student), 0);//&stu取stu地址,(char*)转化为char类型的指针
//方法二:或者增加一个中间变量sendBuff[]来传送,如下
//char sendBuff[1024];
//memset(sendBuff,0,sizeof(sendBuff));
//memcpy(sendBuff, &stu, sizeof(Student));
//send(m_sclient, sendBuff, sizeof(sendBuff), 0);
III.接收方代码(服务端)
struct Student stu; //声明一个结构体变量,用于接收客户端(发送方)发来的数据
//方法一:(推荐)
recv(clientSocket, (char*)&stu, sizeof(Student), 0);
//方法二:
//char buffFromClient[1024]; //用于临时接收发送方的数据
//memset(buffFromClient,0,sizeof(buffFromClient));
//recv(clientSocket, buffFromClient, sizeof(Student), 0);
//memset(&stu,buffFromClent,sizeof(Student));
1.2 使用类对象
I.添加StudentInfo类
注意:(发送方和接收方都需要定义相同结构的类对象)
//StudentInfo.h文件如下,.cpp文件自行实现
#pragma once
#include <iostream>
using namespace std;
class StudentInfo
{
private:
int m_iId;
string m_strName;
bool m_bSex;
public:
StudentInfo();
~StudentInfo();
int GetId();
string GetName();
bool GetSex();
void SetId(int iId);
void SetName(string strName);
void SetSex(bool bSex);
};
II.发送方代码(客户端)
初始化类对象并发送数据
//初始化stuInfo类对象
StudentInfo stuInfo;
stuInfo.SetId(111);
stuInfo.SetName("abcdefzzzzz");
stuInfo.SetSex(true);
send(m_clientSocket, (char*)&stuInfo, sizeof(StudentInfo), 0);
II.接收方代码(服务端)
定义类对象并接收数据
StudentInfo stuInfo;
int iLenOfRecvData = -1;
//传输类对象数据
iLenOfRecvData = recv(clientSocket, (char*)&stuInfo, sizeof(StudentInfo), 0);
if (iLenOfRecvData > 0) //如果接收的数据不为空
{
cout << stuInfo.GetId() << endl;
cout << stuInfo.GetName() << endl;
cout << stuInfo.GetSex() << endl;
}