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);
· 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; //宣告一個結構體變數,用於接收客戶端(傳送方)發來的資料
char buffFromClient[1024]; //用於臨時接收傳送方的資料
//方法一:(推薦)
recv(clientSocket, (char*)&stu, sizeof(Student), 0);
//方法二:
//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;
}