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 和 valueserialize 函数将结构体转换为字节流,而 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 使用结构体

I.假设需要传输的结构体数据如下:

注意:(发送方和接收方都需要定义相同的结构体)

 
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;
}

 

posted @ 2024-05-29 11:32  [BORUTO]  阅读(277)  评论(0编辑  收藏  举报