• Advertisement
Sign in to follow this  

Send/Recv struct problems with winsock2 udp.

This topic is 2295 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm getting started writing a simple server/client for my game. I'm using WINSOCK2 and sending stuff using UDP. I send a custom struct as a packet and the integers are getting read right but the float and string are turning out to garbage on other end.

Here's the struct I'm sending.
struct dataStruct
{
string characters;
int number1;
int number2;
float floaty;
};


Here's the server class.
class UDP_Server
{
public:
dataStruct *recvPacket,*sendPacket;

UDP_Server(void){ }

~UDP_Server(void){ WSACleanup(); }

int recvData(void);
int sendData(void);

void Init(void)
{
recvPacket = new dataStruct;
sendPacket = new dataStruct;

if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
{
printf( "Server: WSAStartup() failed with error %d\n", WSAGetLastError());
printf( "Program shutting down." );
system("PAUSE");
exit(1);
}
else
printf( "WSAStartup() successful!\n" );
serverInf.sin_family = AF_INET;
serverInf.sin_addr.s_addr=INADDR_ANY;
serverInf.sin_port=htons(8888);
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

if( sock == INVALID_SOCKET )
{
printf("Server: Socket -> sock = INVALID_SOCKET! Cleaning up and closing.\n");
WSACleanup();
system("PAUSE");
exit(1);
}
else
printf("Server: socket() is OK.\n");

if (bind(sock, (struct sockaddr*)&serverInf, sizeof(serverInf)) == SOCKET_ERROR)
{
printf("Server: bind() failed with error %d\n", WSAGetLastError());
WSACleanup();
system("PAUSE");
exit(1);
}
else
printf("Server: bind() is OK.\n");

DWORD nonBlocking = 1;
if ( ioctlsocket( sock, FIONBIO, &nonBlocking ) != 0 )
{
printf( "Server: ioctlsocket() failed to set non-blocking socket.\n" );
WSACleanup();
system("PAUSE");
exit(1);
}
else
printf( "Server: Successfully set socket to non-blocking mode.\n\n" );

}
private:
SOCKET sock;
WSADATA wsaData;
struct sockaddr_in serverInf;
};
int UDP_Server::recvData(void)
{
printf("Server: Starting recvData().\n");

int servInf_Len = sizeof(serverInf);
int recv_bytes = recvfrom( sock, (char*)recvPacket, sizeof(struct dataStruct), 0, (struct sockaddr *)&serverInf, &servInf_Len);
dataStruct *recvBuffer = new dataStruct;
recvBuffer = (struct dataStruct*)recvPacket;
if( recv_bytes > 0 )
{
printf("Server: Received packet! Received number1: %d, Received number2: %d, Received float: %d, Received chars: %d with size of: %d \n",recvBuffer->number1,recvBuffer->number2,recvBuffer->floaty,recvBuffer->characters,recv_bytes);
}
else
{
if( recv_bytes < 0 )
{
printf( "Server: Didn't receive any data, recvData() ended with error code: %d\n",WSAGetLastError());
}
}
return recv_bytes;
};

int UDP_Server::sendData(void)
{
printf("Starting sendData().\n");
sendPacket->characters = "Server to client";
sendPacket->floaty = 5.0f;
sendPacket->number1 = 1;
sendPacket->number2 = 2;
int servInf_Len = sizeof(serverInf);

int send_bytes = sendto( sock, (char*)sendPacket, sizeof(struct dataStruct), 0, (struct sockaddr *)&serverInf, servInf_Len);
if( send_bytes > 0 )
{
printf("Server: Sent %d bytes of data to client.\n",send_bytes);
}
else
{
if( send_bytes < 0 )
{
printf("Server: Didnt send any data, sendData() ended with error code: %d\n",WSAGetLastError());
}
}
return send_bytes;
};


Here's the client class.
class UDP_Client
{
public:
dataStruct *recvPacket,*sendPacket;

UDP_Client(void){ }

~UDP_Client(void){ WSACleanup(); }

int recvData(void);
int sendData(void);

void Init(void)
{
net::Address address(127,0,0,1,8888);
recvPacket = new dataStruct;
sendPacket = new dataStruct;
addr = inet_addr("localhost");

if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
{
printf( "Client: WSAStartup() failed with error %d\n", WSAGetLastError());
printf( "Program shutting down." );
system("PAUSE");
exit(1);
}
else
printf( "Client: WSAStartup() successful!\n" );
clientInf.sin_family = AF_INET;
clientInf.sin_addr.s_addr=htonl( address.GetAddress() );
clientInf.sin_port=htons(8888);
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

if( sock == INVALID_SOCKET )
{
printf("Client: Socket -> sock = INVALID_SOCKET! Cleaning up and closing.\n");
WSACleanup();
system("PAUSE");
exit(1);
}
else
printf("Client: socket() is OK.\n");

if ( connect( sock, (struct sockaddr*)&clientInf, sizeof(clientInf) ) == SOCKET_ERROR )
{
printf("Client: connect() failed: %d\n", WSAGetLastError());
WSACleanup();
system("PAUSE");
exit(1);
}
else
printf("Client: connect() is OK.\n");

DWORD nonBlocking = 1;
if ( ioctlsocket( sock, FIONBIO, &nonBlocking ) != 0 )
{
printf( "Client: ioctlsocket() failed to set non-blocking socket.\n" );
WSACleanup();
system("PAUSE");
exit(1);
}
else
printf( "Client: Successfully set socket to non-blocking mode.\n\n" );

}
private:
SOCKET sock;
WSADATA wsaData;
unsigned int addr;
struct sockaddr_in clientInf;

};
int UDP_Client::recvData(void)
{
printf("Client: Starting recvData().\n");
int clientInf_Len = sizeof(clientInf);
int recv_bytes = recvfrom( sock, (char*)recvPacket, sizeof(struct dataStruct), 0, (struct sockaddr *)&clientInf, &clientInf_Len);
dataStruct *recvBuffer = new dataStruct;
recvBuffer = (struct dataStruct*)recvPacket;
if( recv_bytes > 0 )
{
printf("Client: Received packet! Received number1: %d, Received number2: %d, Received float: %d, Received chars: %d with size of: %d \n",recvBuffer->number1,recvBuffer->number2,recvBuffer->floaty,recvBuffer->characters,recv_bytes);
}
else
{
if( (recv_bytes == SOCKET_ERROR) | (recv_bytes < 0) )
{
printf( "Client: Didn't receive any data, recvData() ended with error code: %d\n",WSAGetLastError());
}
}
return recv_bytes;
};

int UDP_Client::sendData(void)
{
printf("Client: Starting sendData().\n");
sendPacket->characters = "Client to Server";
sendPacket->floaty = 5.0f;
sendPacket->number1 = 5;
sendPacket->number2 = 6;

int clientLen = sizeof(clientInf);
int send_bytes = sendto( sock, (char*)sendPacket, sizeof(struct dataStruct), 0, (struct sockaddr *)&clientInf, clientLen);
if( send_bytes > 0 )
{
printf("Client: Sent %d bytes of data to client.\n",send_bytes);
}
else
{
if( send_bytes < 0 )
{
printf("Client: Didnt send any data, sendData() ended with error code: %d\n",WSAGetLastError());
}
}
return send_bytes;
};


If anyone could help me out or give me pointers/advice itd be much appreciated.
Since Ill be programming this all myself and client/server will both know sizes/setups of data being sent/received is there any easier way to send structs or classes containing data?

Share this post


Link to post
Share on other sites
Advertisement
dataStruct is not POD, so you cannot send it by copying its bit pattern. You need to serialise its fields into a contiguous byte array before sending that. An example would be allocating a std::vector<char>, and serialising each field into that. You also need to determine how you are going to represent string data. One option is to use a NUL terminator. You need to be very careful handling this to avoid buffer overflows. Another option would be to prefix the string data with the length. This makes the validation a little easier, and allows you to reserve your string allocation up front without needing to inspect the entire packet twice.

Your code also doesn't appear to take the computer's endian into account.

You should ensure you get at least enough bytes to make up a packet before interpreting the contents as a packet. Failing to do this will result in buffer overflow vulnerabilities, which can be used by a malicious peer to take control of the other peer's computer.

I would recommend using the logical OR operator || rather than the bitwise OR operator | in comparisons.

Share this post


Link to post
Share on other sites
Yes the string var is either an object or struct with a pointer to a dynamic block of the actual string data.
The udp routines just send a contiguous block of bytes (copying into a packet buffer)



If your string data can be longer than the maximum datagram length (~65K , 65,507 ) you will have to send it in more than one send which would likely
require more header info to make the continuation clear to the receiver...


UDP physical packets are really 512 to 1492 data bytes so when you send data up to the max length it will already be fragmenting the
data into multiple physical packets, but you dont have to care about that as the udp routines will automatically reassemble them)

Share this post


Link to post
Share on other sites
If you want more tips on how to fix your network programming code, have a look at the network video tutorials that I posted here: http://www.marek-knows.com/downloads.php5?vmk=network

I just finished posting videos on how to construct a structure used to transmit strings and integers and I'm currently editing the video that shows how to transmit floating point numbers.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement