?
Solved

Read incomming data from a TCP-socket

Posted on 2003-03-27
6
Medium Priority
?
349 Views
Last Modified: 2007-12-19
Hi there,
This time I'm making a client program that connects to a server and sends en receives data from that server. The send part of my program works great, but the receive part (in a thread) doesn't know when there is no data to read anymore or the port is closed. Here is the read-thread I made so far:

----------
DWORD CTCP::ReadThread(LPVOID lpvThreadParm)
{
     unsigned long nDataInQue;

     while(true)
     {
          nReturn = WSAWaitForMultipleEvents(1, &hEventWSA, FALSE, INFINITE, FALSE); //&hEventWSA: see below
          if (nReturn != WAIT_OBJECT_0)
          {
               error.SetError("WSAWaitForMultipleEvents hEventWSA");
          }else{
               error.SetPassed("WSAWaitForMultipleEvents hEventWSA");
          }

          WSANETWORKEVENTS NetworkEvents;
          nReturn = WSAEnumNetworkEvents (sckTCP, NULL, &NetworkEvents); // sckTCP is my socket
          printf("NetworkEvents: %d, ErrorCode: %d\n", NetworkEvents.lNetworkEvents, NetworkEvents.iErrorCode  );
          if (NetworkEvents.lNetworkEvents == FD_CLOSE) printf("FD_CLOSE\n");
          if (NetworkEvents.lNetworkEvents == FD_READ) printf("FD_READ\n");
   
          nReturn = ioctlsocket(sckTCP, FIONREAD, &nDataInQue);
          if (nReturn == SOCKET_ERROR) error.SetWSAError("ioctlsocket()");
          if ((nDataInQue > 0) && (nDataInQue < 1024))
          {
               lpRxData[nRxData] = new char[nDataInQue+1]; //the data is stored in this array
               strcpy(lpRxData[nRxData], "");
               printf("DataInQue: %d\n", nDataInQue);

               nReturn = recv(sckTCP, lpRxData[nRxData], nDataInQue, 0);
               if (nReturn == SOCKET_ERROR)
               {
                    error.SetWSAError("recv()");
               }
               lpRxData[nRxData][nDataInQue] = 0;
               printf("%s", lpRxData[nRxData]);
               nReturn = SetEvent(hEventRxReady);
               if (nReturn == 0)
               {
                    error.SetError("SetEvent hEventRxReady");
               }else{
                    error.SetPassed("SetEvent hEventRxReady");
               }
          }else{
               printf("No or too much data in que (%d), one extra recv done\n", nDataInQue);
               nReturn = recv(sckTCP, lpRxData[nRxData], nDataInQue, 0);
               if (nReturn == SOCKET_ERROR)
               {
                    error.SetWSAError("recv");
               }
          }
     }

     return 0;
}
----------

The event is created before I connect:

----------
nReturn = WSAEventSelect(sckTCP, hEventWSA, FD_READ | FD_CLOSE);
if (nReturn == SOCKET_ERROR)
{
     error.SetWSAError("CreateWSAEvent hEventWSA");
     return false;
}else{
     error.SetPassed("CreateWSAEvent hEventWSA");
}
----------

This gives:

----------
PASSED SetEvent hEventRxReady
PASSED WSAWaitForMultipleEvents hEventWSA
NetworkEvents: 0, ErrorCode: 11665188
No or too much data in que (0)
ERROR in recv: A non-blocking socket operation could not be completed immediatel
y.

ERROR in WSAWaitForMultipleEvents hEventWSA: The handle is invalid.

PASSED WaitForSingleObject hRxReady
NetworkEvents: 0, ErrorCode: 11665188
¼&#9658;è
No or too much data in que (0)
.
.
.
(and so on)
----------

Can somebody explain what I did wrong and how to fix it? If you need some more code or comments from me, just ask!
I'm a newbee, so please be gentle ;-)

Greetz,
Sven.
0
Comment
Question by:Svens
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
6 Comments
 
LVL 12

Expert Comment

by:Salte
ID: 8217935
If you try to read from a socket that is closed in the other end, it means just that.

Just close your end of the socket and consider the transfer complete.

If you had expected more data from the other end than what you got it is possible that the connection broke due to some network failure etc if so you should probably save the data you got to some temporary file or something and flag it to the user that you didn't get complete data.

For example in an FTP transfer it is quite normal to just read data from the socket until you get EOF. You get EOF when the socket in the other end is closed. You should then not attempt to read from that socket any more.

Alf
0
 

Author Comment

by:Svens
ID: 8218389
You're on a good track, but I'll add some more info to clear things up:

The problem in my example is that the program passes "WSAWaitForMultipleEvents" and then comes up with 0 in "WSAEnumNetworkEvents" then I check if there is some data in the queue, but there isn't. This repeats until the end of time. When I tested this with a HTTP GET-request (which closes the connection when all data is send), it takes about 30sec. until the CLOSE event is received.
0
 
LVL 12

Accepted Solution

by:
Salte earned 500 total points
ID: 8219275
Appearantly you do not discover that close event properly and then there's some timeouts before it gets to you....

Hmm... What is the '0' you refer to there, would it be possible to detect it by some way there?

I am not sure of the exact details around WaitForMultipleEvents but select() which is implemented by that function will return how many sockets is available for any of the features you are waiting for. So if WaitForMultiple returned in any variable the number of objects that are 'ready' you will know that if it returns that none is ready that most likely the connection is closed.

You should also be aware for a situation like when receiving a HTTP request, I believe the sender will always send the last line and then close the connection, when you read you will successfully read that line, then you will read once again and get EOF and if you read yet another time you will get error that the socket is closed in the other end. So if you are alert and close the socket when you get EOF you should be ok I think. EOF condition on a socket means that you read and get 0 bytes from the read so the read returns 0 could be a hint that it is end of file.

Of course, that assumes that the sender never send 0 byte packets before it is done but HTTP won't do that, nor will any other TCP protocol that I know of.

Some protocols might signal EOF earlier by simply returning fewer bytes than requested. This is typical for protocols that send a block of data (fixed size) each time. A block with smaller length than the fixed size is then a mark for "this is the last". If the blocks of data are all of the fixed size (so the total data transmitted is a multiple of the block length) such protocols will typically send an extra 0 byte block at the end. TFTP does that for example.

FTP data channel will just mark EOF by closing the connection on the other side so when you get the error that the other party has closed the connection it is time to close your side. If you have a select waiting for data this is very unfortunate since you then have to wait until that wait times out before the system understand there will be no more and then check to see if the connection is closed. To avoid this you can try to do this:

When you get that you have data available to read, read those data and then immediately check to see if the connection is done, do a poll on the socket. If you read more, process those data immediately, if you got 'no data yet' go back to sleep and wait for more, if you got 'socket closed in other end' you discovered it immediately and do not go and wait but instead close the connection.

This require you to do a non-blocking read in a loop instead of doing a single read. However, you should do that anyway since if you receive several packets you won't necessarily get a message for each. If you have arranged that you get a WM_ message when there's a packet available on the socket the following might happen:

1. A packet arrives. The system send you a message.
2. Another packet arrives before you have read the first. The system will NOT send you a message.
3. You read ONE packet and then go back to sleep, in waitformultiple, the wait will immediately return.
4. You will process the second packet.

It might be better just to do non-blocking reads in a loop after waking up from WaitForMultiple... and then go back to sleep if you get a return saying no packet available yet.

Alf
0
 
LVL 2

Expert Comment

by:bkrahmer
ID: 8223100
HTTP 1.0 will close the connection after the file is sent.  HTTP 1.1 has a keepalive option.  Clients can usually set what keepalive options they want to use, but some servers will ignore the client's requests.

brian
0
 
LVL 9

Expert Comment

by:tinchos
ID: 9551595
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:

Answered by: Salte

Please leave any comments here within the next seven days.

PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!

Tinchos
EE Cleanup Volunteer
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on th…
C++ Properties One feature missing from standard C++ that you will find in many other Object Oriented Programming languages is something called a Property (http://www.experts-exchange.com/Programming/Languages/CPP/A_3912-Object-Properties-in-C.ht…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
Suggested Courses

777 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question