Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

winsock recv() call

13 views
Skip to first unread message

Reader

unread,
Feb 13, 2000, 3:00:00 AM2/13/00
to
Hi there - I'm trying to write a basic Win32 HTTP server just for
testing purposes. Things seem to be going well, but recv doesn't seem
to be working as I expect. I did the following:

WSAStartup( wVersionRequested, &wsaData );

SOCKET sock;
sock = socket(AF_INET, SOCK_STREAM, NULL);

SOCKADDR_IN sin;
u_short alport = 80;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = 0;
sin.sin_port = htons(alport);
int nBind = bind(sock, (LPSOCKADDR)&sin, sizeof (sin));

SOCKET sockAccept;
sockaddr incoming;
int incoming_size = sizeof(sockaddr);

while (true)
{
listen(sock, SOMAXCONN);
sockAccept = accept(sock, &incoming, &incoming_size);
char buf[1024];
int nBytesReceived = 0;

problem here ....................................................
nBytesReceived = recv(sockAccept, buf, 1024, 0);
InterpretHTTP(buf, sockAccept);
}

WSACleanup();

This seems to be working just fine as long as the recv buffer is large
enough to handle the incoming request. If it's not, though (if I set
the buffer size to 10, just to test my code), recv returns 10 rather
than SOCKET_ERROR followed by WSAEMSGSIZE (as the documentation
suggests it should).

Am I skipping a step somewhere?

Thanks!

Deano

unread,
Feb 13, 2000, 3:00:00 AM2/13/00
to
Im quite new to winsock programming myself but i think you have to call recv
as long as bytes received is > 0. I cant show you the code as i use vb and
am not very good at c but i can show you a vb code example to check if
theres more data to receive

Public Function IsDataAvailable() As Boolean
Dim readfds As fd_set, writefds As fd_set, exceptfds As fd_set
Dim timeout As TIME_VAL
Dim lngResult As Long, nfds As Long

nfds = 0
timeout.tv_sec = 25
timeout.tv_usec = 0

readfds.fd_count = 1
readfds.fd_array(0) = Sock
writefds.fd_count = 0

exceptfds.fd_count = 0

lngResult = ws_select(nfds, readfds, writefds, exceptfds, timeout)
If lngResult = SOCKET_ERROR Then
SetLastErrorCode = "Error in IsDataAvailable::select"
IsDataAvailable = False
Else
If lngResult > 0 Then IsDataAvailable = True Else IsDataAvailable =
False
End If
End Function

I just use a loop checking to see if this function returns true, and if it
does perform another recv.

If this is a slow way of doing it or I just talking utter crap then any
better ways would be helpful

Cheers,
Dean


Reader <nob...@nowhere.net> wrote in message
news:38a92ec9...@news3.newscene.com...

Fish

unread,
Feb 14, 2000, 3:00:00 AM2/14/00
to
Reader posted the following to alt.winsock.programming:

Probably. :) (Hint: check out 'ioctlsocket')

Winsock will return to you as much data as is available up to the amount
you ask for.

That is, if there is *more* than X bytes, it will only give you X bytes
because that's all you asked for. (i.e. it's *not* considered an error to
ask for *less* than how much there actually is).

(Besides, it can't very well give you *more* than you asked for! If it did,
it would overflow your buffer! Thus it will only give you as much as it has
up to however much you ask for.)

On the flip side, if there is *less* than X bytes available, it can only
give you however much it has and no more. (Duh!)

Thus the reasoning for passing back how much it actually gave you via the
return code (which can be different from however much you asked for).

If you ask for X bytes and the return code from 'recv' is *less* than X
bytes, you're done; that's all there is.

(Note: of course you'll have to check for both cases of SOCKET_ERROR and
the case where 'recv' returns 0 bytes, indicating the connection has been
gracefully closed by the other end).

If you ask for X bytes and 'recv' returns you X bytes, you got all you
asked for, BUT... there *could* (as in *maybe* but not necessarily) be
still more waiting to be read.


What you should probably be doing is using 'ioctlsocket' with the FIONREAD
option to find out how much there actually *is* so you can read it *all*:


// Block until there's some data to be read...

char peek;
int nRetCode;

if ((nRetCode = recv(sock,&peek,1,MSG_PEEK)) != 1)
{
if (nRetCode == 0)
{
// Connection has been closed...
}

// else SOCKET_ERROR; handle appropriately...
}


If the above 'recv' returns '1', it worked; there's data on the socket
waiting to be read. Now what you need to do is find out *how much* data
there is. Use 'ioctlsocket' for that:


unsigned long nBytesAvail;

if (ioctlsocket(sock,FIONREAD,&nBytesAvail) == SOCKET_ERROR)
{
// Error; handle appropriately...
}


Now you know how much there actually is. To read it all in at once, simply
create a buffer large enough and read it in!


char* pBuffer = new char[nBytesAvail];

int nBytesRead = recv(sock,pBuffer,nBytesAvail,0);

if (nBytesRead == SOCKET_ERROR)
{
delete [] pBuffer;
// handle error appropriately...
}

// Process data in pBuffer....


> Thanks!

You're welcome. :)

--

"Fish" (David B. Trout)

(spamblocks in place; actual
e-mail address follows below)

fish.at.infidels.dot.org

Fish

unread,
Feb 14, 2000, 3:00:00 AM2/14/00
to
Yes, I'm replying to my own post, folks; I forgot to mention something in
my original reply...


Fish posted the following to alt.winsock.programming:

<snip my original reply>

I'm also hoping that we're not seeing all of your code here. I'm hoping
that you simply snipped out the portion of your code that closes the socket
when it's done with it (before 'accept'ing the next connection request).

Your loop, as you present it above, will eventually run out of sockets.
Each 'accept' creates a brand new socket and I don't see where you're
closing the "sockAccept" socket before reusing it in the next 'accept'.

(For that matter, I don't see where you're ever closing your listening
socket -- 'sock' -- either.)

As I said, I'm assuming you just trimmed that logic out before making your
post. :)

(I just thought I'd mention that in case anyone else out there trying to
learn sockets programming makes the mistake of copying your "technique.")

Stefaan A Eeckels

unread,
Feb 14, 2000, 3:00:00 AM2/14/00
to
In article <38a92ec9...@news3.newscene.com>,

nob...@nowhere.net (Reader) writes:
> Hi there - I'm trying to write a basic Win32 HTTP server just for
> testing purposes. Things seem to be going well, but recv doesn't seem
> to be working as I expect. I did the following:
>
> WSAStartup( wVersionRequested, &wsaData );
>
> SOCKET sock;
> sock = socket(AF_INET, SOCK_STREAM, NULL);
^^^^^^^^^^^
This means you're using TCP. No concept of messages here,
just a stream of data, without record boundaries. The
UDP protocol uses the concept of messages (SOCK_DGRAM)

<pruned>



> problem here ....................................................
> nBytesReceived = recv(sockAccept, buf, 1024, 0);
> InterpretHTTP(buf, sockAccept);
> }
>
> WSACleanup();
>

> This seems to be working just fine as long as the recv buffer is large
> enough to handle the incoming request. If it's not, though (if I set
> the buffer size to 10, just to test my code), recv returns 10 rather
> than SOCKET_ERROR followed by WSAEMSGSIZE (as the documentation
> suggests it should).

When using TCP, you cannot rely on the recv() call to return
messages. You read a number of bytes, and look for the record
terminator sequence (CR LF). Typically, you use a loop to
read bytes from the socket, and you stop when you see the
terminating sequence. Feel free to be more efficient by buffering
the stream in your program, although with HTTP it doesn't really
make a difference (but with today's really long URLs it might :-).

I'd suggest you buy a good book (the late W Richard Stevens' books
are classics) to learn about socket programming fundamentals.

Take care,

--
Stefaan
--
--PGP key available from PGP key servers (http://www.pgp.net/pgpnet/)--
Ninety-Ninety Rule of Project Schedules:
The first ninety percent of the task takes ninety percent of
the time, and the last ten percent takes the other ninety percent.

0 new messages