I am trying to send struct over tcp socket. I am a newbie in socket programming, I did try the options suggested here already but those did not serve my purpose. Could someone pls help?
I have written Server.cpp and Client.cpp and both are compiling properly. However, when I am executing my Server to listen to the Client, I am not sure if the Server is able to recieve the structure from Client or not. Also, how can I read this structure once it is received?
Server.cpp
#include<iostream>
#include <cstring>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string>
#include<stdio.h>
using namespace std;
int main()
{
struct UE
{
string Net;
int imsi;
} ;
UE UE2;
//cout<<UE1.imsi<<"\n"<<UE1.Net<<"\n";
int sock, cli, receive;
sockaddr_in server, client;
unsigned int len;
if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Socket:");
exit(-1);
}
server.sin_family = AF_INET;
server.sin_port = htons(10000);
//cout<<htons(10000);
server.sin_addr.s_addr = INADDR_ANY;
//cout<<INADDR_ANY;
memset(&(server.sin_zero), '\0', 8);
len = sizeof(struct sockaddr_in);
if((bind(sock, (struct sockaddr *)&server, len)) == -1)
{
perror("Bind:");
exit(-1);
}
if((listen(sock, 5)) == -1)
{
perror("Listen:");
exit(-1);
}
while(1)
{
cli = accept(sock,(struct sockaddr *)&client, &len);
if(cli == -1)
{
perror("Accept");
exit(-1);
}
receive = recv(sock, (void*)&UE2, sizeof(UE2), NULL);
cout<<UE2.imsi;
//cout<<UE2.imsi<<"\n"<<UE2.Net;
//int sent = send(cli, (const void*)&mesg, sizeof mesg, 0);
//cout<<"Sent"<<sent<<" bytes to client :<<inet_ntoa(client.sin_addr)";
close(cli);
}
}
Client.cpp
#include <arpa/inet.h>
#include<iostream>
#include <cstring>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string>
#include<stdio.h>
using namespace std;
int main(int argc, char *argv[])
{
struct UE
{
string Net;
int imsi;
} ;
UE UE1;
UE1.Net = "4G";
UE1.imsi = htons(8649);
int sock, receive;
struct sockaddr_in server;
char mesg[200];
if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Socket:");
exit(-1);
}
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[2]));
//cout<<server.sin.port;
server.sin_addr.s_addr = inet_addr(argv[1]);
//cout<<server.sin_addr.s_addr;
memset(&(server.sin_zero), '\0', 8);
if(connect(sock, (struct sockaddr*)&server, sizeof(server)) == -1)
{
perror("Connect:");
exit(-1);
}
int count = 0;
while(count = 0)
{
send(sock, &UE1, sizeof(UE1), 0);
//receive = recv(sock, (void*)&mesg, sizeof mesg, NULL);
count++;
}
cout<<"Sent "<<UE1.imsi<<" and "<<UE1.Net<<" to Server \n";
close(sock);
}
There are at least 2 problems in your code:
You cannot send objects like std::string
and anything that contains it this way (formally non-POD data), you need to marshall your data. There are plenty of libraries around (like google proto buffers) or you can write your own. This topic is too wide to cover it in the answer here.
You cannot expect that you receive data from TCP stream by the same chunk you sent it, you must write code that can handle receiving data by pieces (and send it that way as well).
You should never ever write a whole struct to a file or a socket. Always write each field separately, and read them the same way. When doing it this way you pay some memory overhead, but it's generally a good design for performance reasons because you don't want to do a write of each value to the socket.
When sending binary data you should always take care for the following things:
You need some functions like the following:
virtual MESSAGE_BUFFER * GetMessageAsBinaryPtr()
{
MESSAGE_BUFFER * binaryMsg = new MESSAGE_BUFFER;
UINT8 * ptrBuffer = &(*binaryMsg)[0];
ptrBuffer = this->serializeUInt16(ptrBuffer, this->m_majorVersion);
ptrBuffer = this->serializeUInt16(ptrBuffer, this->m_minorVersion);
ptrBuffer = this->serializeUInt32(ptrBuffer, (UINT32)this->m_messageType);
ptrBuffer = this->serializeUInt64(ptrBuffer, this->m_packetID);
ptrBuffer = this->serializeDouble(ptrBuffer, this->m_timestamp);
return binaryMsg;
}
virtual void CreateFromBinary(MESSAGE_BUFFER buffer)
{
UINT8 * ptrBuffer = &buffer[0];
ptrBuffer = this->deserializeUInt16FromBuffer(ptrBuffer, &this->m_majorVersion);
ptrBuffer = this->deserializeUInt16FromBuffer(ptrBuffer, &this->m_minorVersion);
UINT32 messageType = 0;
ptrBuffer = this->deserializeUInt32FromBuffer(ptrBuffer, &messageType);
this->SetMessageType((MessageTypes)messageType);
ptrBuffer = this->deserializeUInt64FromBuffer(ptrBuffer, &this->m_packetID);
ptrBuffer = this->deserializeDoubleFromBuffer(ptrBuffer, &this->m_timestamp);
}
inline UINT8 * serializeUInt16(UINT8 * buffer, UINT16 value)
{
buffer[1] = value;
buffer[0] = value >> 8;
return buffer + 2;
}
inline UINT8 * deserializeUInt16FromBuffer(UINT8 * buffer, UINT16 * pOutput)
{
*pOutput = (*pOutput << 8) + buffer[0];
*pOutput = (*pOutput << 8) + buffer[1];
return buffer + 2;
}
When you have such functions you can serialize and deserialize your structs to a buffer and then send this buffer over your socket.
A few points to note:
There are few bugs in your code. In server.cpp sockaddr_in
--> struct sockaddr_in
Once connection request is accepted by server
using accept()
call, it returns new file descriptor , with that new fd you should do read
and write
operation not with old one.
Replace below statement
receive = recv(sock, (void*)&UE2, sizeof(UE2), NULL); /** you are receiving with old fd called sock **/
with
receive = recv(cli, (void*)&UE2, sizeof(UE2), NULL);
client.cpp
using namespace std;
int main(int argc, char *argv[])
{
struct UE
{
string Net;
int imsi;
} ;
UE UE1;
UE1.Net = "4G";
UE1.imsi = htons(8649);
int sock, receive;
struct sockaddr_in server;
char mesg[200];
sock = socket(PF_INET, SOCK_STREAM, 0);
perror("Socket:");
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[2]));
server.sin_addr.s_addr = inet_addr(argv[1]);
memset(&(server.sin_zero), '\0', 8);
connect(sock, (struct sockaddr*)&server, sizeof(server));
perror("Connect:");
int count = 0;
send(sock, &UE1, sizeof(UE1), 0);
perror("send");
cout<<"Sent "<<UE1.imsi<<" and "<<UE1.Net<<" to Server \n";
close(sock);
}
server.cpp
using namespace std;
int main()
{
struct UE
{
string Net;
int imsi;
} ;
UE UE2;
int sock, cli, receive;
struct sockaddr_in server, client;
unsigned int len;
sock = socket(AF_INET, SOCK_STREAM, 0);
perror("Socket:");
server.sin_family = AF_INET;
server.sin_port = htons(10001);
server.sin_addr.s_addr = INADDR_ANY;
memset(&(server.sin_zero), '\0', 8);
len = sizeof(server);
bind(sock, (struct sockaddr *)&server, len);
perror("Bind:");
listen(sock, 1);
perror("Listen:");
cli = accept(sock,(struct sockaddr *)&client, &len);
perror("accept");
receive = recv(cli, ( void*)&UE2, sizeof(UE2), 0);
perror("recv");
cout << "rec = "<<receive<<endl;
cout<<UE2.imsi<<"\n";
close(sock);
perror("close");
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.