CSocket - incomplete data (again)
Hi
I have an odd situation I hope someone could point me in the right direction with. Basically I have a client tcp application that is CSocket (SOCK_STREAM) based, and there is a well defined protocol between the client and server.
Unfortunately there are instances where the data sent to the client application (viewed via a sniffer program) seem not to be completely received. The server may send data at certain intervals in response to a client request: when the client has had enough, it will issue a request to terminate the data where upon the server will issue a confirmation string.
For example, server sends
AB
AB
CDEF // termination confirmation
client reads AB, AB, and EF: expected AB, AB, and CDEF;
server sends
ABC
ABC
DEFGHI // termination confirmation
client reads ABC, ABC, and GHI: expected ABC, ABC, DEFGHI.
I am not sure if it is a coincidence that the number of characters chopped off in the final string happen to be the the number of characters read in the preceding string.
When I view return values from the socket reads, they look OK: in the second example above, the final read returns 3 for GHI, but I expected 6!
Has anyone seen anything similar? or can suggest any courses of action?
Re: CSocket - incomplete data (again)
Any piece of code from your receive and send function can be helpful to find out problem.
what is the size of buffer you r using while receiving data .
try to use receive function like this.
Code:
char * buff=new char[10239]; // Creating buffer for receiving msg
UINT uSize=10240; // Size of created buffer
UINT uReceived=0; // variable which will receive actuall received bytes
//******************************************
//******************************************
/**/uReceived=this->Receive(buff,uSize);//** Socket's Receive function for receiveing data with buffer and size parameters
//******************************************
//******************************************
if(uReceived!=SOCKET_ERROR) // if Receive function return value is not SOCKET_ERROR
{
buff[uReceived]=NULL; // putting NULL at the end of actual received bytes
CString msg;
msg.Insert(0,buff); // putting that received bytes into msg string
}
CSocket::OnReceive(nErrorCode);
Re: CSocket - incomplete data (again)
Hi
Here is the recv and send code in use. MAX_BUFFER is 4096.
void CJPSocket::OnReceive(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
int nRead;
memset(buff, 0x00, MAX_BUFFER);
nRead = Receive(buff, MAX_BUFFER);
switch (nRead)
{
case 0:
Close();
break;
case SOCKET_ERROR:
if (GetLastError() != WSAEWOULDBLOCK)
{
AfxMessageBox ("Error occurred");
Close();
}
break;
default:
buff[nRead] = '\0';
m_data.push_back(buff);
}
m_owner->PostMessage(m_idmRead);
std::stringstream ss;
ss << "recv returned: " << nRead;
AfxMessageBox(ss.str().c_str());
CSocket::OnReceive(nErrorCode);
}
void CJPDlg::OnButtonSend()
{
// TODO: Add your control notification handler code here
std::stringstream ss;
CString windowText;
m_editRaw.GetWindowText(windowText);
ss << (LPCTSTR)windowText;
if (m_socket.Send(ss.str().c_str(), ss.str().length()) == SOCKET_ERROR)
AfxMessageBox("Could not send data to socket!");
}
Re: CSocket - incomplete data (again)
check the return value of your send function. because send function return total number of char sended.
Quote:
When I view return values from the socket reads, they look OK: in the second example above, the final read returns 3 for GHI, but I expected 6!
if you receive 3 characters insted of 6 then most probebly your send function is sending 3 characters.
Re: CSocket - incomplete data (again)
Quote:
Originally Posted by ABDULNAUMAN
...if you receive 3 characters insted of 6 then most probebly your send function is sending 3 characters.
ABDULNAUMAN: I think the OP already has confirmed that send() is working properly, since he mentioned that he saw the correct transmission using a packet sniffer.
jpeltrie: Please confirm the above, and here's what I think is happening.
First and foremost, you must remember that TCP is a "streaming" protocol, not a message-based protocol. The significance of this is that you cannot expect each and every send() to result in a corresponding transmission and a corresponding recv(). For example, consider a situation where your server makes three separate calls to send() as follows:
ABC
ABC
DEFGHI
That could be transmitted over the "wire" in a variety of ways:
(a) nothing is transmitted yet because winsock is "collecting" transmissions (maybe the Nagle algorithm)
(b) one packet of ABC\nABC\nDEFGHI
(c) two packets: a first of ABC\nABC\nDEF and then a second of GHI
(d) etc (anything you can think of and more)
In actuality, you're probably sending your strings with a NULL terminator (and not the newline \n character as I used above). So, if that's the case, here's what might be happening:
(1) Your server sends ABC\0 and ABC\0 goes out over the wire and is successfully received by the client.
(2) Your server sends ABC\0 and nothing goes out over the wire yet
(3) Your server sends DEFGHI\0 and winsock transmits ABC\0DEF over the wire
3(a) your client receives ABC\0DEF and stuffs it into buff and then adds \0 to it, so now buff contains ABC\0DEF\0
3(b) you push_back buff, but since it's nothing more than a NULL-terminated string, the push_back value gets truncated to ABC\0 and you effectively lose the rest
(4) winsock finally gets around to transmission of GHI\0 which is successfully received by the client.
The end result is that although you Sent ABC\0ABC\0DEFGHI\0, your client looks like it only received ABC\0ABC\0GHI\0 (i.e., the DEF is missing).
To test if this is what's happening, check strlen(buff) against nRead, which is the number of bytes read by the Receive() function. You would expect them to be identical, right? I'll bet they're not.
Mike
Re: CSocket - incomplete data (again)
Hi
Thanks for the replies!
I have been bitten by NULL characters a long time ago, so I usually look for these (although not demonstrated in the code snippet provided in a previous post).
Unfortunately, the number of characters read by the Receive command happens to equal the string length of the buffer extracted, and thus I have been doubly puzzled. The server sends the appropriate characters, too!
Maybe the solution will come to me in a dream.
jp
Re: CSocket - incomplete data (again)
Quote:
Originally Posted by jpeltrie
Hi
Thanks for the replies!
I have been bitten by NULL characters a long time ago, so I usually look for these (although not demonstrated in the code snippet provided in a previous post).
Post something closer to the actual code and we'll take a better look.
Quote:
Originally Posted by jpeltrie
Unfortunately, the number of characters read by the Receive command happens to equal the string length of the buffer extracted, and thus I have been doubly puzzled. The server sends the appropriate characters, too!
I see that in your very first post you stated "the final read returns 3 for GHI, but I expected 6!" That's to be expected, and of course in this case, nRead would be equal to strlen(buff).
But what about in the OnReceive immediately preceding the OnReceive in which GHI was received. That's the call where I would expect nRead to differ from strlen(buff). Are they equal in that call too? Are they equal in all cases?
Mike
Re: CSocket - incomplete data (again)
Keep in mind the blocking nature of CSocket for example
if incoming Data Size was 502 bytes
and u do things like this
Receive(buffer,1024);//CSocket would block here unless it gets complete 1024 data , which in this case will not be there.
also it is not necessary that if you call "Receive(buffer,1024); " you will get the whole data at once , may be you get 500 bytes of total 1024 so u will also have to keep track of actual received bytes (return value from Receive).
so receive all data in loop and as actual read bytes =Data Size break that loop.
another very famouse problem with CSocket is its Fake FD_READ notification while receiving the data in OnReceive event handler , so its better at the start of OnReceive disable FD_READ using AsyncSelect and enable it efter receiving whole data.
Also do see this thread
http://www.codeguru.com/forum/showth...03#post1012603
Re: CSocket - incomplete data (again)
Quote:
Originally Posted by atif_ilm
...
if incoming Data Size was 502 bytes
and u do things like this
Receive(buffer,1024);//CSocket would block here unless it gets complete 1024 data , which in this case will not be there.
This is not correct. It's true that a blocking socket will not return from a call to Receive() until winsock is finished with your buffer, even if winsock was not ready for you when the call to Receive came in. But that's not the same as saying that the buffer will be filled completely, and it might be or it might not. Winsock tells you how many bytes it gave you in the return value of Receive(), and that might be the full value of the buffer or it might be less, down to a single byte sometimes, but never less than something.
That's one difference from a non-blocking socket. A non-blocking socket, OTOH, will return immediately with either data in your buffer or possibly zero data. In the latter case, there's a GetLastError of WSAEWOULDBLOCK for which you're required to test.
Quote:
Originally Posted by atf_ilm
also it is not necessary that if you call "Receive(buffer,1024); " you will get the whole data at once , may be you get 500 bytes of total 1024 so u will also have to keep track of actual received bytes (return value from Receive).
so receive all data in loop and as actual read bytes =Data Size break that loop.
This is true, and read how it differs from what you said just above.
Quote:
Originally Posted by atif_ilm
another very famouse problem with CSocket is its Fake FD_READ notification while receiving the data in OnReceive event handler , so its better at the start of OnReceive disable FD_READ using AsyncSelect and enable it efter receiving whole data.
I don't know what you mean by this. If you disable FD_READ then you have disabled the entire message-based notification system by which winsock signals your app that there's data to be read. IOW, when when FD_READ is set, winsock sends a WM_SOCKETEVENT message (I think that's the message) to your app which eventually finds its way to CSocket. The CSocket framework in response calls the virtual OnReceive() function. Without FD_READ, winsock would not send the message to initiate this func6tionality.
Quote:
Originally Posted by atif_ilm
That thread gives demonstrably bad information. Some is correct, but most is not.
Mike
Re: CSocket - incomplete data (again)
Hi
Thanks for the input.
I can only guess this is an application level error that has thus far confused me.
I agree that an embedded NULL character would screw things up, but upon interrogating send and recv return codes, the received data, and the packet sniffer information, I am reasonably confident that something may be happening beyond the application's control :)
Here is another situation:
Server sends
ABCDEF // client receives all data (accumulating if necessary)
5 second wait
GHI // client does not register data
5 second wait
JKL // client does not register data
5 second wait
MNO // client registers data
It is a coincidence that strlen(ABCDEF) == strlen(GHI) + strlen(JKL), and only MNO is registered after JKL is sent.
jp