|
In addition to what Mark said, don't expect your Receive call (whatever your particular API is - recv in plain old sockets) to receive all the bytes sent in a single call by the Send. You might get "hel" then "lohelloa" then "gain" in consecutive calls. You must code your receiving logic to handle rebuilding the entire packet that Mark is talking about.
Judy
|
|
|
|
|
Hi JudyL_FL,
I am not sure if I understand what do you mean, by:
"You must code your receiving logic to handle rebuilding the entire packet that Mark is talking about."
I am just using one recv() , so you mean that it is possible that I just get: "hell" and nothing else? Note, I am calling recv() only once.
Thanks.
|
|
|
|
|
bigdenny200 wrote: I am just using one recv(), so you mean that it is possible that I just get: "hell" and nothing else? Note, I am calling recv() only once.
Exactly. There is no guarantee that a single recv call on one end of a connection will get all the data sent with a single send call on the other end. Looking at the reply you sent to Mark, you need to keep calling recv until you get your "end of packet" marker ;. Handle that packet somewhere somewhen and repeat the process.
Judy
|
|
|
|
|
JudyL_FL wrote: There is no guarantee that a single recv call on one end of a connection will get all the data sent with a single send call on the other end.
It is possible with fixed sized messages, and blocking sockets. Although, I don't think the message sizes are fixed, because he mentions parsing messages, separated with a ;
--
Kein Mitleid Für Die Mehrheit
|
|
|
|
|
I could fix their lengths Jorgen, i.e. if I have "bye" I could remake it to "bye**" and remove two stars later. here block size would be 5. Is that what you mean ?
Thanks
|
|
|
|
|
Yes, but looking at it that way (with text based commands and all), it's smarter to take the buffered approach. That way you don't lock yourself down in case you need to change the protocol.
|
|
|
|
|
Joergen Sigvardsson wrote: It is possible with fixed sized messages
Not guaranteed. Even with fixed sized messages, there's NO guarantee the TCP protocol
won't deliver it in different size chunks. Only a datagram protocol guarantees this.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
He is right if it is a blocking socket. If you ask for x bytes in the recv function, it will either deliver x bytes or return a timeout indication.
Judy
|
|
|
|
|
What's a blocking socket?
Thanks Judy!!
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Some mythical beast that I've heard about and know the legends about but have never encountered in real life.
|
|
|
|
|
Well Judy, I had to test this before I respectfully disagreed with you
I respectfully disagree... A blocking Recv() WILL return before all bytes requested are
received.
Here's the test I did - note I try to recv 512 bytes but only send 256...
<font color="Green">
<font color="Green">
</font>UINT __cdecl TestThreadProc( LPVOID pParam )
{
SOCKET ListenSocket;
ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ListenSocket == INVALID_SOCKET)
{
return 1;
}
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("127.0.0.1");
service.sin_port = htons(2460);
if (bind( ListenSocket, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR)
{
closesocket(ListenSocket);
return 1;
}
if (listen( ListenSocket, 1 ) == SOCKET_ERROR)
{
closesocket(ListenSocket);
return 1;
}
SOCKET AcceptSocket;
AcceptSocket = accept( ListenSocket, NULL, NULL );
if (AcceptSocket == INVALID_SOCKET)
{
closesocket(ListenSocket);
return 1;
}
BYTE *pBuf = new BYTE[512];
BYTE *pCurBuf = pBuf;
int BytesRemaining = 512;
while (BytesRemaining > 0)
{
int CurBytesReceived = ::recv(AcceptSocket, (char*)pCurBuf, BytesRemaining, 0);
if (CurBytesReceived == 0) <font color="Red">
{
break;
}
else if (CurBytesReceived == SOCKET_ERROR)
{
int rc = WSAGetLastError();
if (rc != WSAEWOULDBLOCK)
{
break;
}
}
else
{
BytesRemaining -= CurBytesReceived;
pCurBuf += CurBytesReceived;
}
}
delete[] pBuf;
closesocket(AcceptSocket);
closesocket(ListenSocket);
return 0;
}
<font color="Green">
void CMYTestDlg::OnOK()
{
AfxBeginThread(&TestThreadProc, NULL);
::Sleep(1000); <font color="Red">
SOCKET ConnectSocket;
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ConnectSocket == INVALID_SOCKET)
{
return;
}
sockaddr_in clientService;
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr( "127.0.0.1" );
clientService.sin_port = htons( 2460 );
if ( connect( ConnectSocket, (SOCKADDR*) &clientService, sizeof(clientService) ) == SOCKET_ERROR)
{
return;
}
BYTE *pBuf = new BYTE[512];
send(ConnectSocket, (const char *)pBuf, 256, 0);
delete[] pBuf;
::MessageBox(*this, _T("Waiting for socket receive :-P"), _T("Waiting"), MB_OK);
closesocket(ConnectSocket);
return;
}
I had to know before I changed the way I answer socket questions here - I'm nuts like that
Cheers,
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Can you try calling WSAGetLastError after you receive the partial bytes? I'm curious if it is set to show the timeout. According to the documentation, recv should either read all or timeout. The docs do say:
Windows Sockets 2 does not define any standard blocking time-out mechanism for this function
I think we're hitting this case - the receive has timed out and who knows how the function is reporting the timeout. I think we can safely say the following:
For a blocking socket, you need to check the result from the recv and if you don't get the requested number of bytes, you have hit the timeout condition and need to handle it accordingly.
Judy
|
|
|
|
|
JudyL_FL wrote: Can you try calling WSAGetLastError after you receive the partial bytes?
Sure
WSAGetLastError() returns 0;
A long time ago, while writing some of my first communication code, I got bit by this (using pipes actually,
but it made me look at my sockets code) and it taught me to read the documentation thoroughly (which I
wasn't doing apparently ). That's when I found this:
"For connection-oriented sockets (type SOCK_STREAM for example), calling recv will return as much data
as is currently available—up to the size of the buffer specified."
FWIW, This also applies to pipes.
So, any amount of bytes returned by recv() indicates success. This can be seen especially when receiving
amounts larger than the socket buffer, where the protocol MUST return a buffer full of data to make room to
receive more.
This seems to be the number one thing overlooked by beginner socket programmers.
I studied MS's implementation of TCP a while back, and there is a timeout involved internally, but it's
not an error of any kind. I believe by default it's 200ms (that's the number that comes to mind) before
a recv() returns what it has currently buffered. That's what makes it inefficient to always request more
bytes than you're expecting.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Mark Salsbery wrote: WSAGetLastError() returns 0;
I was curious - it was easier to have you check since you had working code. How long does your recv sit before it returns? Never mind, it's not important. I vaguely remember some socket I did a looooong while back that (I think) waited a whole lot longer than your 200ms. Too far in the past to remember the details or if I had set a timeout value or it was using the built-in one. This may have been on CE, now that I think about it and that's a whole 'nother kettle of sockets. If it wasn't CE, it was long enough ago that it was at least as old as NT4.
I think we have our answer - always check the number of bytes received
Judy
|
|
|
|
|
JudyL_FL wrote: was curious - it was easier to have you check since you had working code.
I knew that hehe.
JudyL_FL wrote: How long does your recv sit before it returns?
About a second (accurate, huh?) from when I hit the OK button - that includes the 1000ms Sleep() in my fancy thread
synchronization.
I agree it doesn't matter - the internal "timeout" is implementation specific. Different protocol stack vendors are free to
implement the internals the way they want. That's why I only have MS specific info (and even that is vague now).
recv() API behavior, however, is well defined.
JudyL_FL wrote: I think we have our answer - always check the number of bytes received
Agreed!
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Mark Salsbery wrote: and it taught me to read the documentation thoroughly
BTW, I wasn't implying that you don't read the docs - I meant that was a turning
point for me, which is why I remember it vividly
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
no offense taken (especially since I quoted the docs a reply or so back), have a .... wait, where's the beer emoticon??? aaaargh
Judy
|
|
|
|
|
|
Right you are on both accounts - one recv will do if you know the packet size and the OP is not using a fixed size packet
|
|
|
|
|
I have encountered a weird namespace alias resolution bug(?) in VC++ 2003. I'm getting error C2653: 'innernamespace' : is not a class or namespace name for Orhun::Func2 (Commented out in the code provided below). Note that Func3, which is not a class method, with similar signature compiles just fine...
VC++ 2005 compiles all 3 functions without any errors.
Is this a known problem with 2003? My searches failed to return any meaningful results.
namespace topnamespace
{
namespace innernamespace
{
class Foo
{
public:
Foo() {}
Foo(int i) {}
};
}
}
namespace orh = topnamespace::innernamespace;
class Orhun
{
void Func1(orh::Foo e = topnamespace::innernamespace::Foo(-1))
{
}
};
void
Func3(orh::Foo e = orh::Foo(-1))
{}
Orhun Birsoy
|
|
|
|
|
It compiles fine on VS 2008 too.
Looks like a bug to me...I don't know if it's known or not though.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Hello, Orhun Birsoy.
I resolved the problem using "using namespace":
...
namespace orh = topnamespace::innernamespace;
using namespace topnamespace; // Added
class Orhun{
...
I guess, later versions of Visual Studio are equipped with the facility which do "using namespace" automatically for namespaces declared in same file.
But I consider its original to use "using namespace" for ur example. For example, we have a havit "using namespace std;" after "#include list or map".
**SnowFall**
-- modified at 22:45 Wednesday 14th November, 2007
|
|
|
|
|
I have to appoint an integer variable to another integer pointer itself. I tried this:
<br />
sNumber& DrawNumber()
{<br />
<br />
sNumber* pNum = new sNumber;<br />
pNum->i1 = edi1;<br />
pNum->i2 = edi2;<br />
<br />
}<br />
sNumber& sn = DrawNumber();<br />
for(int i=0; i<2; i++)<br />
{<br />
int x1 = sn.pNum[i]; <br />
int x2 = sn.pNum[i];<br />
}<br />
How much its right or wrong? have you got other any bookmarks on this topic? I have no possibility to compile this codes.
-- modified at 13:28 Wednesday 14th November, 2007
Was is das¿
|
|
|
|
|
I'm going to have to go with it is a lot wrong, but can't say where because I have no idea what you are asking.
|
|
|
|
|
Well abase... You are mean that it is impossible to appoint an integer variable to an integer pointer. Anyone can help me?
Was is das¿
|
|
|
|