如何打包和解包这个tcp客户端的结构



我需要一些帮助来创建要在客户端和服务器之间来回发送的结构,主要是打包和拆包。我不确定我是否正确创建了结构,因为我不确定消息部分是否正确。分组报头是versiontypelength,它们的大小都是4个字节,并且data是最大10个字节。

struct header {
uint32_t version;
uint32_t type;
uint32_t msgLen;                        
};
struct data {
uint32_t message;
};

int main(int argc, char **argv)
{
if(argc < 2) {
cerr << "Error enter command line format: $ server -p 6543 -l LOGFILE" << endl;
return 0;
}
int port;
port = atoi(argv[1]);
if(port <= 1000)
{
cerr << "Port > 1000 required." << endl;
return(1);
}
cout << "Port correct" << endl;
// get logfile name
char* charString = argv[2];
string logFile(charString);
// Create socket.
int sockfd,newSockfd;
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
cerr << "Socket error." << endl;
return(1);
}
cout << "Socket Correct" << endl;
struct sockaddr_in serverAddr,clientAddr;
// Clear the server address structure.
memset((void *) &serverAddr, 0, sizeof(serverAddr));
int yes = 1;
if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
// Set up the server address structure.
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddr.sin_port = htons(port);
//create and error check bind
if(bind(sockfd, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) < 0) {
cerr << "Bind error." << endl;
return(1);
}
cout << "binding successful" << endl;
//listen
listen(sockfd,10);
cout << "listening" << endl;
unsigned int clientLen;
unsigned int version,type;
char* recHead,*recMsg;
struct header h;
struct data d;
h.version = 1;
h.type = 1;
h.msgLen = 5;
d.message = 3;
while(1) {
clientLen = sizeof(clientAddr);
newSockfd = accept(sockfd, (struct sockaddr *) &clientAddr, &clientLen);
if(newSockfd < 0) 
{
cerr << "Accept error." << endl;
exit(1);
}
char *ip;
ip = inet_ntoa(clientAddr.sin_addr );
fstream outFile(logFile,std::fstream::in | std::fstream::out | std::fstream::app);
outFile << "Received connection from IP: " << ip << endl << "PORT: " << ntohs(clientAddr.sin_port) << endl;
//recieve emessage
recHead =recieveMsg(newSockfd,logFile);
cout << endl << endl << recHead << endl << endl;
recMsg = recieveMsg(newSockfd,logFile);
string check(recHead);
//ignore capitals
std::transform (check.begin(), check.end(), check.begin(), ::tolower);
string network = "network";
string quit = "quit";
//check for word network
char buffer[18];
htonHeaderData(h, d,buffer);
if (check.find(network) != std::string::npos) { 
cout << "ugh" << endl;
send(newSockfd,buffer,18, 0);
}
if (check.find(quit) != std::string::npos) {            
//exit the server
close(sockfd);
exit(1);
}
outFile.close();
}
close(sockfd);
}
//beginning functions to keep the code clean
//receive message
char* recieveMsg(int clientSock, string logFile){
int msgSize;
char buffer[1024]; 
// Clear the buffer.
memset(buffer, '', 1024); 
cout << "Receiving Message" << endl;
if((msgSize = recv(clientSock, buffer, 1023, 0)) < 0) 
{
cerr << "Error receiving the message." << endl;
}
char* msgRcv=(char*)malloc(sizeof(buffer));
sprintf(msgRcv, "%s", buffer);
// Clear the buffer.
memset(buffer, '', 1024); 
return msgRcv;
}
void htonHeader(struct header h, char buffer[12]) {
uint32_t u32;
u32 = htonl(h.version);
memcpy(buffer+0, &u32, 4);
u32 = htonl(h.type);
memcpy(buffer+4, &u32, 4);
u32 = htonl(h.msgLen);
memcpy(buffer+8, &u32, 4);
}
void htonData(struct data d, char buffer[10]) {
uint32_t message1;
message1 =htonl(d.message);
int size = sizeof(message1);
if (size > 10){
cout << "Message is too large" << endl;
return;
}
memcpy(buffer+0, &message1, size);
}
void htonHeaderData(struct header h, struct data d, char buffer[16]) {
htonHeader(h, buffer+0);
htonData(d, buffer+12);
}

recv()不能保证返回您要求的所有字节。它可以返回更少的字节。因此,您需要在一个循环中调用recv(),直到收到您期望的所有字节。header的大小是固定的,假设它的msgLen告诉您以下data的大小。因此,您可以很容易地知道recv()需要多少字节。

此外,来自recv()的数据不是以null结尾的字符串,但您的代码将其视为以null结尾。

试试类似的东西:

struct header {
uint32_t version;
uint32_t type;
uint32_t msgLen;                        
};
struct data {
uint32_t message;
};

int main(int argc, char **argv)
{
if (argc < 2) {
cerr << "Error enter command line format: $ server -p 6543 -l LOGFILE" << endl;
return 0;
}
int port = atoi(argv[1]);
if (port <= 1000)
{
cerr << "Port > 1000 required." << endl;
return(1);
}
cout << "Port correct" << endl;
// get logfile name
string logFile = argv[2];
// Create socket.
int sockfd, newSockfd;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
cerr << "Socket error." << endl;
return 1;
}
cout << "Socket Correct" << endl;
sockaddr_in serverAddr, clientAddr;
// Clear the server address structure.
memset(&serverAddr, 0, sizeof(serverAddr));
int yes = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
cerr << "setsockopt error." << endl;
close(sockfd);
return 1;
}
// Set up the server address structure.
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddr.sin_port = htons(port);
//create and error check bind
if (bind(sockfd, (sockaddr*) &serverAddr, sizeof(serverAddr)) < 0) {
cerr << "Bind error." << endl;
close(sockfd);
return 1;
}
cout << "binding successful" << endl;
//listen
if (listen(sockfd, 10) < 0) {
cerr << "Listen error." << endl;
close(sockfd);
return 1;
}
cout << "listening" << endl;
socklen_t clientLen;
header recHead;
data recData;
ofstream outFile(logFile, std::ofstream::app);
while (true) {
clientLen = sizeof(clientAddr);
newSockfd = accept(sockfd, (sockaddr*) &clientAddr, &clientLen);
if (newSockfd < 0) 
{
cerr << "Accept error." << endl;
close(sockfd);
return 1;
}
outFile << "Received connection from IP: " << inet_ntoa(clientAddr.sin_addr) << ", PORT: " << ntohs(clientAddr.sin_port) << endl;
//receive message
if (receiveMsg(newSockfd, recHead, recData, outFile) <= 0) {
close(newSockfd);
continue;
}
// use recHead and recData as needed...
}
close(sockfd);
return 0;
}
//beginning functions to keep the code clean
int receiveRaw(int sock, void *buffer, size_t bufsize){
char *pbuffer = (char*)buffer;
int numRead;
while (bufsize > 0)
{
if ((numRead = recv(sock, pbuffer, bufsize, 0)) <= 0) 
return numRead;
pbuffer += numRead;
bufsize -= numRead;
}
return 1;
}
int sendRaw(int sock, const void *buffer, size_t bufsize){
const char *pbuffer = (const char*)buffer;
int numSent;
while (bufsize > 0)
{
if ((numSent = send(sock, pbuffer, bufsize, 0)) < 0) 
return numSent;
pbuffer += numSent;
bufsize -= numSent;
}
return 0;
}
//receive header
int receiveHeader(int sock, header &h, ostream &logFile) {
logFile << "Receiving Header" << endl;
char buffer[12];
int res;
if ((res = recieveRaw(sock, buffer, 12)) <= 0)
logFile << "Error receiving the header." << endl;
else
ntohHeader(buffer, h);
return res;
}
//send header
int sendHeader(int sock, const header &h, ostream &logFile) {
logFile << "Sending Header" << endl;
char buffer[12];
htonHeader(h, buffer);
int res;
if ((res = sendRaw(sock, buffer, 12)) < 0)
logFile << "Error sending the header." << endl;
return res;
}
//receive data
int receiveData(int sock, const header &h, data &d, ostream &logFile) {
logFile << "Receiving Data" << endl;
if (h.msgLen > 10)
{
logFile << "Message is too large." << endl;
return -1;
}
char buffer[10];
int res;
if ((res = recieveRaw(sock, buffer, h.msgLen)) <= 0)
logFile << "Error receiving the message data." << endl;
else
ntohData(buffer, d);
return res;
}
//send data
int sendData(int sock, const header &h, const data &d, ostream &logFile) {
logFile << "Sending Data" << endl;
if (h.msgLen > 10)
{
logFile << "Message is too large." << endl;
return -1;
}
char buffer[10];
htonData(d, buffer);
int res;
if ((res = sendRaw(sock, buffer, h.msgLen)) < 0)
logFile << "Error sending the message data." << endl;
return res;
}
//receive message
int receiveMsg(int sock, header &h, data &d, ostream &logFile)
{
int res;
if ((res = receiveHeader(sock, h, logFile)) == 1)
res = receiveData(sock, h, d, logFile);
return res;
}
//send message
int sendMsg(int sock, const header &h, const data &d, ostream &logFile)
{
int res;
if ((res = sendHdr(sock, h, logFile)) == 0)
res = sendData(sock, h, d, logFile);
return res;
}
void htonHeader(const header &h, char buffer[12]) {
uint32_t u32;
u32 = htonl(h.version);
memcpy(buffer+0, &u32, 4);
u32 = htonl(h.type);
memcpy(buffer+4, &u32, 4);
u32 = htonl(h.msgLen);
memcpy(buffer+8, &u32, 4);
}
void ntohHeader(char buffer[12], header &h) {
uint32_t u32;
memcpy(&u32, buffer+0, 4);
h.version = ntohl(u32);
memcpy(&u32, buffer+4, 4);
h.type = ntohl(u32);
memcpy(&u32, buffer+8, 4);
h.msgLen = ntohl(u32);
}
void htonData(const data &d, char buffer[10]) {
uint32_t u32 = htonl(d.message);
memcpy(buffer+0, &u32, sizeof(u32));
}
void ntohData(char buffer[10], data &d) {
uint32_t u32;
memcpy(&u32, buffer+0, sizeof(u32));
d.message = ntohl(u32);
}

最新更新