![]() |
| | #1 |
| Registered User Join Date: Nov 2007
Posts: 3
| recv() malfunctioning in a pthread? I've got a simple client and simple server setup going. Right now, my client uses send() twice: first to send a header, and then to send a request. I know that this functionality is working correctly (I'll explain later). On the server side, I started simple; just had a while(1) loop accepting new connections and then recv()'ing the two send()'s. This worked just fine, and I could pull all the data that was sent and print it out to ensure it was correct. However, to allow for multiple requests to be processed at once, I wanted to detach a new pthread for every connection I had incoming. So I did something like this: Code: void *processRequest (void* arg) {
int socket = (int) arg;
char buf1[100];
recv(socket, buf1, 100, 0);
char buf2[100];
recv(socket, buf2, 100, 0); // BLOCKS HERE
close(socket);
// Do stuff with the buffers here.
}
int main() {
// Set up socket stuff here
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 1024*1024);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
while(1) {
int connection = accept(socket, null, null);
pthread_t thread;
pthread_create (&thread, &attr, processRequest, (void *) connection);
}
}
Thanks. |
| th3void is offline | |
| | #2 |
| Registered User Join Date: Mar 2003
Posts: 3,902
| How big is the header and how big is the payload? You are prob. reading both wth the first recv. gg |
| Codeplug is online now | |
| | #3 |
| Senior software engineer Join Date: Mar 2007 Location: Portland, OR
Posts: 5,768
| I don't see anything wrong that would cause this to stop working just because you started using threads. A few things though: Don't cast the "connection" descriptor to void * to pass it to the thread function. Casting between integer and pointer types works on some platforms but not everywhere. Going from int to void * to int again could lose information. Instead you should be passing an address of some kind. Allocate a little buffer to store the connection number and pass a pointer to that instead. Do NOT just pass a pointer to the connection variable itself. It might get overwritten by an immediately following connection before the first thread gets a chance to extract its value. In other words, that's a race condition. You also don't check the return value of recv(). The call to recv() is not guaranteed to actually return 100 bytes -- it could return less. It may require multiple calls to read all the data. Alternately you could pass MSG_WAITALL to try to read all the bytes in one call, but it still might error. You have to check. And why do these very simple threads need a 1 megabyte stack? |
| brewbuck is offline | |
| | #4 |
| and the hat of Jobseeking Join Date: Aug 2001 Location: The edge of the known universe
Posts: 21,693
| > my client uses send() twice: first to send a header, and then to send a request. But there's no reason for the receiver to see that division. It's like reading a file, you have no idea how the file was written (a byte at a time, a line at a time). All you see is a stream of bytes, and that's it. For recv(), it might take one call to get all the data, it might take 3 or 4. Even if it takes 2 calls, there's no reason to assume that it matches the packet sizes you sent. ALL the responsibility for parsing the stream rests with you. The network just transports it in packets which are convenient to transport, and reassembles the stream in the order it was sent. You should also be aware that send() doesn't guarantee to send the whole message in one call, so you need to pay close attention to that return result as well. |
| Salem is offline | |
| | #5 |
| Registered User Join Date: Nov 2007
Posts: 3
| Thanks for the response, guys. t brewbuck: You are correct that I will need to eventually allocate for that int, I am still in the testing phase and I was sure that at least the part that passed the connection number was working fine. To all three of you, well, you were right in that I should be checking the value of recv(). However, I'm still a bit confused. The header is variable length unfortunately. It's a username and then an int to describe the size of the payload. More on this later. What is bothering me is the following: if I execute the two recv() calls directly from the while() loop, rather than creating a thread, the first recv() returns 9 bytes and the second recv() returns 50. If I do this in the pthread instead, the first returns 59 bytes (and as Codeplug mentioned, this is both send()'s which is why it is blocking). I guess I was incorrect in thinking that each recv() would only process the output from one send(); whoops. However, since this is the case, do either of you have any parsing suggestions? Since we can see from running directly in the while() loop it appears there is no guarantee both packets have been sent by the time I call the first recv(), I'm not sure how to decide whether or not I need a second recv(). And because the header isn't fixed length I don't know how to tell recv() ONLY to pull the data from the header with the first call. Yick... |
| th3void is offline | |
| | #6 |
| Registered User Join Date: Mar 2003
Posts: 3,902
| The client typically needs to know how much data it can expect to recieve. Since the header is variable length, then the first member of the header could be "size of header". Then you just need functions for "send till it's sent" and "read till it's read" ![]() gg |
| Codeplug is online now | |
| | #7 |
| and the hat of Jobseeking Join Date: Aug 2001 Location: The edge of the known universe
Posts: 21,693
| You need something in the data stream to tell you where the boundaries are. For example, HTML separates the header from the body with a blank line. In the first instance, you just accumulate data until that is seen (and save whatever comes after it for later), then parse the header. Another way is to prefix each message with a length, so you can read say 1 or 2 bytes initially, then know how many more to expect for the next 'frame' of data. |
| Salem is offline | |
| | #8 |
| Registered User Join Date: Nov 2007
Posts: 3
| Ah, well admittedly this is a tiny, tiny bit of a school project that I'm working on. This recv() message problem had stumped me for more than 8 hours now (dumb, I know) so I'm glad you were able to assist on that. As far as the message headers, I can't really alter their structure as it's specified in the assignment, so that'll be a big pain in the rear. I'll slave away for a few more days and see if I can't get anything cranked out. Thanks for all of your help. |
| th3void is offline | |
![]() |
| Thread Tools | |
| Display Modes | |
|
Similar Threads | ||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Question about recv | carrotcake1029 | Networking/Device Communication | 2 | 02-26-2009 02:10 PM |
| Pthread recv Blocks | scioner | C Programming | 6 | 03-13-2008 08:45 PM |
| The Pthread Hell | matott | Linux Programming | 1 | 04-10-2005 05:59 AM |
| recv() | afisher | Networking/Device Communication | 3 | 03-24-2004 05:32 PM |
| non blocking recv | rohit | Linux Programming | 4 | 03-05-2002 09:35 PM |