Sign in to follow this  
cherryhouse

sending... sending... stop.

Recommended Posts

I'm having a problem with my tcp server which seems to be having a problem receiving/sending data after the clients send a bunch of messages at once. Well actually, the messages can be pretty spread apart, but the server still seems to "lockup" until the user who was causing the mass packet, gets kicked or leaves the server. I know tcp is "special" for receiving everysingle packet, and wont move on until all packets have been received, but is there anyway I could speed the speed of the server so it doesn't take so long to receive, process data, then send to the clients again? The server is used almost continuously and will most likely be flooded like this if I use it in a real situation if I put it out for people to use at the point it's at. Perhaps a message queue would be the best situation in this case? Is there any nice solutions that I could be pointed towards, since I'm not exactly sure what I'm looking for at this point? Thanks in advanced. EDIT: I was just thinking, if I used separate sockets for sending and receiving data, would that reduce the "intensity" of this problem? currently, I have one socket(sockfd) to send data and receive data. [Edited by - cherryhouse on April 16, 2006 10:43:55 PM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Are you using blocking sockets? If so, are you using the select() mechanism to ensure that data is waiting on the socket you are calling recv() on?

It sounds to me that what you are experiencing may not be a flooding problem.

A blocking socket will sit there in the recv() function until it gets some data to return. If there is no data there, it will sit in that function until someone sends something.

Either use nonblocking sockets, or use the select() function to determine which sockets have data waiting, and only call recv() on those sockets.

Share this post


Link to post
Share on other sites
Are you using blocking recv() calls? I don't see why sending and receiving should cause each other grief otherwise. I always use separate sockets for separate clients because it fries my brain to think about it otherwise, and it does avoid this sort of thing.

Share this post


Link to post
Share on other sites
I'm using select.

The reason I think the server is flooding is because if a client types
Quote:
hdf
dfjhsd
rehdf
hdfh
dfh
dfhdfsjr
jdfj
dshjfdjhre
hdfjfg
fndf
hredherd
jhdfjg
jrjtrf
j
ghjrdt
jdfj
fgj
djr
tj
fg
d

line breaks being the user pressed enter to send to the server


really quickly, the server doesn't receive anymore messages or send anymore messages until that user leaves(I think I said that already).

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
that small amount of data isn't going to flood your server unless you have teeny tiny buffers and are polling extremely slowly.

In your example, you only have 114 bytes..

I think something is pushing your server into ain infinite loop. Might be your game logic, or might be an issue with a blocking socket.

Can you run your sever through a debugger? when it lockes up pause your debuffer and look at your stack trace. Where in your code did it stop?

perhaps your parser on your server has some bugs in it?

Share this post


Link to post
Share on other sites
you do have a bug somewhere in your code.
I think you should post some code so we can investigate this behavior.

Nuno1

Share this post


Link to post
Share on other sites
This is the code that deals with all the sending and receiving that locks up after a bit

void Server::ServLoop()
{
// Begin loop
for(;;)
{
// Replace slave fd from master fd
slave = master;
// Check sockets for existing data to be read
if (select(fdmax+1, &slave, NULL, NULL, NULL) == -1){
// Check file descriptor and handle messages
Msges.ErrorMsg("Socket selecting failed.");
return;}
// Null all characters in your recv buffer
for(int p = 0; p < 256; p++) recvbuf[p] = '\0';

// Check sockets for activity
for(i = 0; i <= fdmax; i++)
{
// Check to see if the file descriptor is in the set
if (FD_ISSET(i, &slave))
// If listener receives data from socket i...
if (i == listener)
{
// Accept client attempting to connect
Accept_client();
} else {
// Receive message or remove client from server
Recv_msg();
}
}
}
}

// Accept a client into the server
void Server::Accept_client()
{
// Copy remote_address bytes to addrlen
addrlen = sizeof(remote_address);
// Accept connecting client from listener socket
if ((newfd = accept(listener,
(sockaddr *) &remote_address,
&addrlen)) == -1)
// Output error message if accept fails
{ Msges.ErrorMsg("Accept failed.");
} else {
// If client accept goes successful, add client socket to set
FD_SET(newfd, &master);
// Set max fd to newfd(max user)
if (newfd > fdmax) { fdmax = newfd; }
// Set user ip address in vector
tempuser.ip = inet_ntoa(remote_address.sin_addr);
// Receive client username
recv(newfd, recvbuf, 15, 0);
// Set client username in vector
tempuser.name = recvbuf;
// Set client socket
tempuser.id = newfd;
// Add client to vector
my_vec.push_back(tempuser);
// Output user join message and socket connected on
Msges.JoinMsg(tempuser.name, newfd);
}
}

// Receive a message from a client
void Server::Recv_msg()
{
// Receive buffer on character array recvbuf
if ((bytes = recv(i, recvbuf, 512, 0)) <= 0)
{
// If no data received, remove client from userlist
Remove_client(); // There's no problem with this code
} else {
// If data was received, send to all users
Send_msg();

}
}

// Send a message to (a) client(s)
void Server::Send_msg()
{
// Loop through vector and send message to all users
for(int h = 0; h < my_vec.size(); h++)
{
// Set temporary socket as i
tempuser.id = i;
// Set tempuser2 as temporary vector for comparing
tempuser2 = my_vec.at(h);
// If sockets match, display username of vector position and message
if(tempuser2.id == tempuser.id)
{
strcpy(tempstr, tempuser2.name.c_str());
strcat(tempstr, ": "); strcat(tempstr, recvbuf);
strcpy(recvbuf, tempstr);
}
}

// Loop through all sockets
for(j = 0; j <= fdmax; j++)
{
// if socket j is in the set, send to that socket
if (FD_ISSET(j, &master))
{
// Send recvbuf to all users
send(j, recvbuf, sizeof(recvbuf), 0);
}
}
}

Share this post


Link to post
Share on other sites
I have taken a fast look at your code, the first thing that jump right at me is that you expect to recieve all the message at once.

if ((bytes = recv(i, recvbuf, 512, 0)) <= 0)
{
// If no data received, remove client from userlist
Remove_client(); // There's no problem with this code
} else {
// If data was received, send to all users
Send_msg();

}

TCP work with streams , you should never expect to recieve all of the data in one packet. you should make sure that all of the data has been arrived. for example , you better send the length of the message before the message itself so your application will receive data until the the number of bytes recieved equals to the length.

it also possible to do this while waiting for end-of-line character.

this may put your server in a very strange state and may result with your problem.


write a receive function as I mention and give it a try.

good luck
Nuno1

Share this post


Link to post
Share on other sites
int size;
recv(i, recvbuf, size, 0);
size = atoi (recvbuf);
do{
if ((bytes = recv(i, recvbuf, sizeof(recvbuf), 0)) <= 0)
{
// If no data received, remove client from userlist
Remove_client(); // There's no problem with this code
} else {
// If data was received, send to all users
Send_msg();

}
}while(size > sizeof(recvbuf));


I tried this, didn't quite work out as well as it should have. I sent a bunch of messages and the server didn't stop responding while I was sending them(don't know if I sent enough) but when I would send messages fairly quickly, the size of the buffer would appear in the message once the client received it.

example: user output
Quote:
hello //typing each character every second
h1e1l1l1o //typing "hello" quickly, messages get "mixed" up


Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I'm not sure that you are making the assumption that you get all data as the previous poster asserted. Your check for a socket that has it's FD_ISSET as true but does not return data is a correct check for a disconnected socket.

What seems odd to me is this code:

if (newfd > fdmax) { fdmax = newfd; }
// Set user ip address in vector
tempuser.ip = inet_ntoa(remote_address.sin_addr);
// Receive client username
recv(newfd, recvbuf, 15, 0);
// Set client username in vector
tempuser.name = recvbuf;
// Set client socket
tempuser.id = newfd;
// Add client to vector
my_vec.push_back(tempuser);
// Output user join message and socket connected on
Msges.JoinMsg(tempuser.name, newfd);
}

This code will block on recv(), although it only happens on accept.. so probably not your problem.

You also cannot assume your fd's will be consecutive integers, instead of doing loops from 0 to fd_max, I would cycle through the list of fds you have accepted (looks like the .id member of the structures in your vector)

You are sending to the other clients the contents of your entire recieve buffer. You should only send the amount of data you have recieved, not sizeof(recvbuffer)

Also, your select function will block until it recieves data, unless you set the last parameter to a non-null value.


Ok.. this may be the culprit:


for(int p = 0; p <

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Oops.. got attacked by bad source tags.. reposting...


I'm not sure that you are making the assumption that you get all data as the previous poster asserted. Your check for a socket that has it's FD_ISSET as true but does not return data is a correct check for a disconnected socket.

What seems odd to me is this code:

if (newfd > fdmax) { fdmax = newfd; }
// Set user ip address in vector
tempuser.ip = inet_ntoa(remote_address.sin_addr);
// Receive client username
recv(newfd, recvbuf, 15, 0);
// Set client username in vector
tempuser.name = recvbuf;
// Set client socket
tempuser.id = newfd;
// Add client to vector
my_vec.push_back(tempuser);
// Output user join message and socket connected on
Msges.JoinMsg(tempuser.name, newfd);
}


This code will block on recv(), although it only happens on accept.. so probably not your problem.

You also cannot assume your fd's will be consecutive integers, instead of doing loops from 0 to fd_max, I would cycle through the list of fds you have accepted (looks like the .id member of the structures in your vector)

You are sending to the other clients the contents of your entire recieve buffer. You should only send the amount of data you have recieved, not sizeof(recvbuffer)

Also, your select function will block until it recieves data, unless you set the last parameter to a non-null value.


Ok.. this may be the culprit:


for(int p = 0; p < 256; p++) recvbuf[p] = '\0';



Seems to indicate that your buffer is 1024 bytes big.


if ((bytes = recv(i, recvbuf, 512, 0)) <= 0)



is only pulling a max of 512 bytes off of the stream


send(j, recvbuf, sizeof(recvbuf), 0);



is sending your entire 1024 byte buffer

depending on how fast you are typing, and how many packets are actually being generated, i suppose it's possible that you could be filling your buffer, as you are not reading all of your data each frame.

I would change your


if ((bytes = recv(i, recvbuf, 512, 0)) <= 0)



to a


while ((bytes = recv(i, recvbuf, 512, 0)) <= 0)



and see if performance increases

Share this post


Link to post
Share on other sites
changing the if statement to while does increase performance quite noticably, but it still stops receiving after the client sends too many messages. How would I stop the buffer from being filled? How would I "reset" the buffer so that this doesn't happen?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
can you post your header as well as your source file? I'd like to compile your app and see if i get the same behavior.

Share this post


Link to post
Share on other sites
I'm thinking about making the switch over to udp(even though it's quite...ridiculous)seeing that my server seems to get hung up on single packets being sent and lost in a loop.

Share this post


Link to post
Share on other sites
One thing that helps with buffer overruns is ensuring nagling is disabled - when enabled, TCP apparently sends data but in effect queues it into a single packet for transmission. This can cause you to not send enough (a truncated packet)(send will return less than the buffer provided) which if you're not catching will result in an expected recieve of longer than your actual received (transmitted data) and a blocked socket on the recipient (server).

Set TCP_NODELAY on your sockets and see if that fixes it, and turn off the blocking.



Share this post


Link to post
Share on other sites
You're not checking the return value from the first recv. If it's less than you're expecting you're in trouble!

Networking is one area where being completely obsessed with every return value you can get pays off. You need to know what is being sent when, and what is being received at the other end.

EDIT: Try dumping the incoming and outgoing streams to file or stdout/printf. May help in seeing what's going on.

Share this post


Link to post
Share on other sites
Wow, I can't believe I didn't see it before... I feel like an idiot :(.

send(j, recvbuf, sizeof(recvbuf), 0);

I don't think I have to explain the problem to anybody.

Thanks for all the help.

Share this post


Link to post
Share on other sites

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