Advertisement

sending... sending... stop.

Started by April 16, 2006 09:59 PM
16 comments, last by cherryhouse 18 years, 10 months ago
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]
Hello?
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.
Advertisement
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).
Hello?
you do have a bug somewhere in your code.
I think you should post some code so we can investigate this behavior.

Nuno1
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 = '\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 servervoid 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 clientvoid 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);        }    }}
Hello?
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
Advertisement
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 userlistRemove_client(); // There's no problem with this code} else {// If data was received, send to all usersSend_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


Hello?
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?
Hello?
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.
Hello?
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.



Winterdyne Solutions Ltd is recruiting - this thread for details!

This topic is closed to new replies.

Advertisement