Sign in to follow this  

SDL_Net: Server - Client Communication

This topic is 2664 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

Hi!

I've been playing around with SDL_Net, trying to get a simple client-server communication model working. Some old threads I've found on this forum have been really helpful to me :)

Currently I've managed to get one server listening for input from multiple clients, however when I try to send this input back to the clients (ie. a simple chat system) the clients that receive this input display nonsense.

I know the problem is probably something really stupid and basic, but I can't for the life of me figure out what it is.

Here's what it looks like on the client window:
Client Window

Here's what it looks like on the server window:
Server Window


Here's the relevant server code:


...

vector<char *> messagesC;

...

void handleNetworkData(Clients &clients, SDLNet_SocketSet socketSet)
{
if(!socketSet){
return;
}

const int timeout = 0;
int active = SDLNet_CheckSockets(socketSet, timeout);
// If there is activity.
if(active > 0){

for(int i = 0; i < clients.size(); i++){

if(TCPsocket client = clients.at(i).getCSD()){

// Check if socket has had some activity
if(SDLNet_SocketReady(client)){

clients.at(i).setLastActiveTick(SDL_GetTicks());

const int bufferSize = 511;
// +1 to ensure there is room for NULL terminator
char buffer[bufferSize + 1];

// Read the data.
int bytes = SDLNet_TCP_Recv(client, buffer, bufferSize);

switch(bytes){

case -1:
// error handling
break;

case 0:
// Socket was closed by remote host.
// Close the socket and null the pointer in the vector.
printf("Host %d disconnected\n\n", i);
SDLNet_TCP_DelSocket(socketSet, client);
SDLNet_TCP_Close(client);
clients.erase(clients.begin()+i);
break;

default:
// We got some data!
// Ensure it is NULL terminated and print.
buffer[bytes] = '\0';
printf("\nClient %d says: %s\n\n", i, buffer);

messagesC.push_back(buffer);

break;
}
}
}
}
}
}

void sendMessages(Clients &clients, SDLNet_SocketSet socketSet){

for(int i=0; i<messagesC.size(); i++){

char *theMessage = messagesC.at(i);
int length = sizeof(messagesC.at(i));

for(int j=0; j<clients.size(); j++){
if (SDLNet_TCP_Send(clients.at(j).getCSD(), theMessage, length) < length){
printf("SDLNet_TCP_Send: %s\n", SDLNet_GetError());
//exit(EXIT_FAILURE);
}
else{
cout << "Message sent on socket " << clients.at(j).getCSD() << " - " << theMessage << ".\n";
}
}
}

messagesC.clear();
}

...






Here's the relevant client code:


...

void recievePackets(){

const int timeout = 0;
int active = SDLNet_CheckSockets(socketSet, timeout);
// If there is activity.
if(active > 0){

if(TCPsocket server = sd){
if(SDLNet_SocketReady(sd)){

const int bufferSize = 511;
// +1 to ensure there is room for NULL terminator
char buffer[bufferSize + 1];

// Read the data.
int bytes = SDLNet_TCP_Recv(sd, &buffer, sizeof(buffer));
//cout << buffer << endl;

switch(bytes){

case -1:
// error handling
break;

case 0:
// Socket was closed by remote host.
// Close the socket and null the pointer in the vector.
cout << "Server %d disconnected\n\n";
SDLNet_TCP_DelSocket(socketSet, sd);
SDLNet_TCP_Close(sd);
break;

default:
// We got some data!
// Ensure it is NULL terminated and print.
buffer[bytes] = '\0';
printf("\nServer says: %s\n\n", buffer);
break;
}
}
}
}
}

...

int main(int argc, char **argv){
...

while (running){
sendPackets();
recievePackets();
}

...
}





Anybody know what is causing the problem?

Share this post


Link to post
Share on other sites
Here are a few observations:

Quote:
vector<char *> messagesC;


Why not just use vector<string> or vector< vector<char> > instead? Rarely do you want an actual vector of raw pointers.

Quote:
int bytes = SDLNet_TCP_Recv(client, buffer, bufferSize);


SDLNet_TCP_Recv will read UP TO bufferSize bytes. It is not guaranteed to read bufferSize bytes in a single call. Consider putting this into a loop and adjusting your write buffer offset accordingly. Same goes for SDLNet_TCP_Recv.

Quote:
int length = sizeof(messagesC.at(i));


This does not do what you think it does. messagesC is a vector of char*, so at(i) returns a char*. sizeof(char*) does not return the length of the array, it returns the size of a char pointer, probably 4 bytes on a 32 bit machine.

Quote:
messagesC.push_back(buffer);


This is most likely the source of your current problem. You are pushing a pointer to automatic memory into your vector. Once char buffer[bufferSize + 1] goes out of scope (at the end of the if block), your vector now contains a pointer to garbage, which is exactly what you see printed out. Either allocate the memory on the heap with new (which requires manual clean up later), or use a structure like vector<string>, vector< vector<char> >, or similar.

[Edited by - CodeMunkie on August 30, 2010 12:57:03 PM]

Share this post


Link to post
Share on other sites
Here's the server code with a few adjustments:


...
vector<string> messages;
...

void sendMessages(Clients &clients, SDLNet_SocketSet socketSet){

for(int i=0; i<messages.size(); i++){

string theMessage = messages.at(i);
int length = theMessage.length();

for(int j=0; j<clients.size(); j++){
if (SDLNet_TCP_Send(clients.at(j).getCSD(), &theMessage, length) < length){
printf("SDLNet_TCP_Send: %s\n", SDLNet_GetError());
//exit(EXIT_FAILURE);
}
else{
cout << "Message sent on socket " << clients.at(j).getCSD() << " - " << theMessage << ".\n";
}
}
}

messages.clear();
}

...

void handleNetworkData(Clients &clients, SDLNet_SocketSet socketSet)
{
if(!socketSet){
return;
}

const int timeout = 0;
int active = SDLNet_CheckSockets(socketSet, timeout);
// If there is activity.
if(active > 0){

for(int i = 0; i < clients.size(); i++){

if(TCPsocket client = clients.at(i).getCSD()){

// Check if socket has had some activity
if(SDLNet_SocketReady(client)){

clients.at(i).setLastActiveTick(SDL_GetTicks());

const int bufferSize = 511;
// +1 to ensure there is room for NULL terminator
char buffer[bufferSize + 1];

// Read the data.
int bytes = SDLNet_TCP_Recv(client, buffer, bufferSize);

switch(bytes){

case -1:
// error handling
break;

case 0:
// Socket was closed by remote host.
// Close the socket and null the pointer in the vector.
printf("Host %d disconnected\n\n", i);
SDLNet_TCP_DelSocket(socketSet, client);
SDLNet_TCP_Close(client);
clients.erase(clients.begin()+i);
break;

default:
// We got some data!
// Ensure it is NULL terminated and print.
buffer[bytes] = '\0';
printf("\nClient %d says: %s\n\n", i, buffer);

messages.push_back(buffer);

break;
}
}
}
}
}
}

...



This code appears to be working as intended. Here's the command prompt output for the server:




Here's what the client command prompt looks like (not so nice):


Here's the client code. I haven't got around to putting SDLNet_TCP_Recv into a loop yet - could you give me a basic example of what this might look like?


...

void recievePackets(){

const int timeout = 0;
int active = SDLNet_CheckSockets(socketSet, timeout);
// If there is activity.
if(active > 0){

if(TCPsocket server = sd){
if(SDLNet_SocketReady(sd)){

const int bufferSize = 511;
string message;

// Read the data.
int bytes = SDLNet_TCP_Recv(sd, buffer, bufferSize);

switch(bytes){

case -1:
// error handling
break;

case 0:
// Socket was closed by remote host.
// Close the socket and null the pointer in the vector.
cout << "Server %d disconnected\n\n";
SDLNet_TCP_DelSocket(socketSet, sd);
SDLNet_TCP_Close(sd);
break;

default:
// We got some data!
printf("\nServer says: %s\n\n", buffer);
break;
}
}
}
}
}

...


Share this post


Link to post
Share on other sites
I don't see where you declared buffer in recievePackets(), and also you declare string message, but you never use it.
Also, I would print out the number of bytes returned from int bytes = SDLNet_TCP_Recv(sd, &buffer, sizeof(buffer)) for debugging purposes so you can validate the length of data you received.

[Edited by - CodeMunkie on August 30, 2010 3:51:47 PM]

Share this post


Link to post
Share on other sites
"& theMessage" is the address of the string class instance, not the address of the first character of the string.

I suggest you go learn a little more about pointers and objects, or your attempts at distributed systems programming (networking, etc) will probably be very painful for lack of required basics.

Share this post


Link to post
Share on other sites

This topic is 2664 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this