Board index » Visual Studio » blocking socket

blocking socket

Visual Studio293
Hi all,



I posted a message earlier regarding using CAsyncSocket

but the received messages are appended or chopped up. I

was suggested to use blocking sockets (by both this

newsgroup and outside this newsgroup) to solve this

problem, but the problem persisted.



What's wrong with my code? Is it doing blocking receive?

How come I still get incomplete messages?



Thanks!!



Here's my code:



#include "stdafx.h"

#include <winsock2.h>



int main(int argc, char* argv[])

{

int SOCK;

struct sockaddr_in pin;

struct timeval tv;

int port = 4;

int ret = SOCKET_ERROR;

char buf[7100];



WSADATA wsaData;

if (NO_ERROR != WSAStartup(MAKEWORD(2,2), &wsaData))

printf("Error at WSAStartup()\n");



pin.sin_family = AF_INET;

pin.sin_addr.s_addr = inet_addr( "1.2.3.4" );

pin.sin_port = htons(port);



SOCK = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);



printf("Connecting to server\n");

if ( connect(SOCK, (SOCKADDR*)&pin, sizeof(pin)) ==

SOCKET_ERROR)

{

printf( "Failed to connect. Error Code = %d\n",

WSAGetLastError() );

WSACleanup();

return -1;

}

printf("Connected.\n");



tv.tv_sec = 3000; setsockopt (SOCK, SOL_SOCKET,

SO_RCVTIMEO, (char*)&tv, sizeof(tv));



while ((0 != ret) || (WSAECONNRESET == ret))

{

if (WSAECONNRESET == WSAGetLastError())

break;



ret = recv(SOCK, buf, 7100, 0);

printf("here");

if ( ret == 0 || ret == WSAECONNRESET )

{

printf( "Connection Closed.\n");

break;

}

printf( "Bytes Recv: %ld\n", ret );

}



WSACleanup();



return 0;

}





The message that I posted earlier:

I am using CAsyncSocket with SOCK_STREAM option (using

TCP). I noticed that in most cases the messages I received

from the other end were ok, but sometimes two messages

were appended together, and sometimes a message was

chopped into two separate messages.



Is that a problem of using CAsyncSocket? Anyway I can fix

it? Do I get the same problem if I don't use CAsyncSocket?

Any suggestions?


-
 

Re:blocking socket

TCP doesn't understand 'messages'... its just a stream of

data.

If you know how big your messages are a priori, keep

reading until you get that much. If you don't, then you'd

typically include a 'size' data at the head of each

message so the receiver knows how much to expect.



You can use UDP for message-based data (but its an

unreliable protocol, meaning some messages may get lost on

the way - depends on the application whether that's

acceptable or not).



Look at ioctlsocket(FIONBIO) to make socket blocking or

not. I don't recall what the default is.



Oh, and by the way, RTFM





Quote
-----Original Message-----

Hi all,



I posted a message earlier regarding using CAsyncSocket

but the received messages are appended or chopped up. I

was suggested to use blocking sockets (by both this

newsgroup and outside this newsgroup) to solve this

problem, but the problem persisted.



What's wrong with my code? Is it doing blocking receive?

How come I still get incomplete messages?



Thanks!!



Here's my code:



#include "stdafx.h"

#include <winsock2.h>



int main(int argc, char* argv[])

{

int SOCK;

struct sockaddr_in pin;

struct timeval tv;

int port = 4;

int ret = SOCKET_ERROR;

char buf[7100];



WSADATA wsaData;

if (NO_ERROR != WSAStartup(MAKEWORD(2,2), &wsaData))

printf("Error at WSAStartup()\n");



pin.sin_family = AF_INET;

pin.sin_addr.s_addr = inet_addr( "1.2.3.4" );

pin.sin_port = htons(port);



SOCK = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);



printf("Connecting to server\n");

if ( connect(SOCK, (SOCKADDR*)&pin, sizeof(pin)) ==

SOCKET_ERROR)

{

printf( "Failed to connect. Error Code = %d\n",

WSAGetLastError() );

WSACleanup();

return -1;

}

printf("Connected.\n");



tv.tv_sec = 3000; setsockopt (SOCK, SOL_SOCKET,

SO_RCVTIMEO, (char*)&tv, sizeof(tv));



while ((0 != ret) || (WSAECONNRESET == ret))

{

if (WSAECONNRESET == WSAGetLastError())

break;



ret = recv(SOCK, buf, 7100, 0);

printf("here");

if ( ret == 0 || ret == WSAECONNRESET )

{

printf( "Connection Closed.\n");

break;

}

printf( "Bytes Recv: %ld\n", ret );

}



WSACleanup();



return 0;

}





The message that I posted earlier:

I am using CAsyncSocket with SOCK_STREAM option (using

TCP). I noticed that in most cases the messages I

received

from the other end were ok, but sometimes two messages

were appended together, and sometimes a message was

chopped into two separate messages.



Is that a problem of using CAsyncSocket? Anyway I can fix

it? Do I get the same problem if I don't use

CAsyncSocket?

Any suggestions?



.



-

Re:blocking socket

So, to summarize:



- if i want to receive a complete "message" (without

appending/chopping up), the only simple way is to use UDP

which is not reliable

- if I use connection-based socket, this problem will

likely occur, whether it's blocking or not

- blocking connection-based socket might help only if I

know ahead of time how big a "message" is so that I know

how many bytes to receive



Correct? If not, please correct me.



Thanks!







Quote
-----Original Message-----

TCP doesn't understand 'messages'... its just a stream of

data.

If you know how big your messages are a priori, keep

reading until you get that much. If you don't, then you'd

typically include a 'size' data at the head of each

message so the receiver knows how much to expect.



You can use UDP for message-based data (but its an

unreliable protocol, meaning some messages may get lost

on

the way - depends on the application whether that's

acceptable or not).



Look at ioctlsocket(FIONBIO) to make socket blocking or

not. I don't recall what the default is.



Oh, and by the way, RTFM





>-----Original Message-----

>Hi all,

>

>I posted a message earlier regarding using CAsyncSocket

>but the received messages are appended or chopped up. I

>was suggested to use blocking sockets (by both this

>newsgroup and outside this newsgroup) to solve this

>problem, but the problem persisted.

>

>What's wrong with my code? Is it doing blocking receive?

>How come I still get incomplete messages?

>

>Thanks!!

>

>Here's my code:

>

>#include "stdafx.h"

>#include <winsock2.h>

>

>int main(int argc, char* argv[])

>{

>int SOCK;

>struct sockaddr_in pin;

>struct timeval tv;

>int port = 4;

>int ret = SOCKET_ERROR;

>char buf[7100];

>

>WSADATA wsaData;

>if (NO_ERROR != WSAStartup(MAKEWORD(2,2), &wsaData))

>printf("Error at WSAStartup()\n");

>

>pin.sin_family = AF_INET;

>pin.sin_addr.s_addr = inet_addr( "1.2.3.4" );

>pin.sin_port = htons(port);

>

>SOCK = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);

>

>printf("Connecting to server\n");

>if ( connect(SOCK, (SOCKADDR*)&pin, sizeof(pin)) ==

>SOCKET_ERROR)

>{

>printf( "Failed to connect. Error Code = %d\n",

>WSAGetLastError() );

>WSACleanup();

>return -1;

>}

>printf("Connected.\n");

>

>tv.tv_sec = 3000; setsockopt (SOCK, SOL_SOCKET,

>SO_RCVTIMEO, (char*)&tv, sizeof(tv));

>

>while ((0 != ret) || (WSAECONNRESET == ret))

>{

>if (WSAECONNRESET == WSAGetLastError())

>break;

>

>ret = recv(SOCK, buf, 7100, 0);

>printf("here");

>if ( ret == 0 || ret == WSAECONNRESET )

>{

>printf( "Connection Closed.\n");

>break;

>}

>printf( "Bytes Recv: %ld\n", ret );

>}

>

>WSACleanup();

>

>return 0;

>}

>

>

>The message that I posted earlier:

>I am using CAsyncSocket with SOCK_STREAM option (using

>TCP). I noticed that in most cases the messages I

received

>from the other end were ok, but sometimes two messages

>were appended together, and sometimes a message was

>chopped into two separate messages.

>

>Is that a problem of using CAsyncSocket? Anyway I can

fix

>it? Do I get the same problem if I don't use

CAsyncSocket?

>Any suggestions?



-

Re:blocking socket

dev wrote:



Quote
So, to summarize:



- if i want to receive a complete "message" (without

appending/chopping up), the only simple way is to use UDP

which is not reliable

- if I use connection-based socket, this problem will

likely occur, whether it's blocking or not

- blocking connection-based socket might help only if I

know ahead of time how big a "message" is so that I know

how many bytes to receive



Correct? If not, please correct me.



Thanks!



You can't change the way connection based sockets work. Write buffering

code to put your messages back together from what you receive.



--

Scott McPhillips [VC++ MVP]



-

Re:blocking socket

Blocking or nonblocking doesn't matter. You have made one of the most common errors of

socket programming, which is the assumption that if I send AAABBBCCC, I will receive only

AAABBBCCC; in fact, the socket levels, blocking or not, are free to return the data sent

in an substream, so you might receive AA ABB BCC CC or any other combination. This is how

TCP/IP is defined to work, and you will have to deal with it. Changing the socket to be a

blocking socket will not solve this problem, but will lead to other problems that are not

worth trying to solve.



The only the wrong with your code is that it makes a fallacious assumption that has no

basis for being made. Assume that messages will be split up arbitrarily in ways you can

neither control nor predict. Given that, you have to come up with a way to determine where

a message boundary is. Some people put a length value in front of the message (and note

that if the length is longer than one byte, you can't even get the length all at once!);

others read until they get a specific terminator (newline is the most common). Using a FSM

model in your OnReceive handler to decide what to receive next is usually suitable. One

algorithm is:

state = READ_0;

switch(state)

{ /* state */

case READ_0: // read 2-byte length

n = Receive(buf, sizeof(WORD));

switch(n)

{ /* READ0_n */

case SOCKET_ERROR: // -1, I think this is the symbol

... deal wth error

case 1:

length = (BYTE)buf[0];

state = READ_1;

return;

case 2:

length = (WORD)&buf[0];

length = ntohs(length); // if big-endian

state = READ_DATA;

pos = 0;

return;

default:

ASSERT(FALSE);

return;

} /* READ0_n */

return;

case READ_1: // read second byte of 2-byte length

n = Recieve(buf, sizeof(BYTE));

switch(n)

{ /* READ1_n */

case SOCKET_ERROR:

... deal with error ...

case 1:

length = length << 8 | buf[0]; // big-endian

// OR

length = buf[0] << 8 | length; // little-endian

state = READ_DATA;

pos = 0;

return;

default:

ASSERT(FALSE);

return;

} /* READ1_n */

return;

case READ_DATA:

n = Receive(&buf[pos], length);

pos += n;

length -= n;

if(length == 0)

{ /* done */

state = READ_0; // reset for next message

...handle message, post notification, whatever...

return;

} /* done */

return;

default:

ASSERT(FALSE); // bad state

} /* state */



There are several equivalent approaches, but I find the FSM the easiest to implement. Note

that the length could be sent in native x86 order, which is little-endian, but it is

considered better practice to send the length in network byte order (htons(length) before

sending the bytes) so it is platform-independent.



Think of the problem of receiving TCP/IP to be identical to the problem of reading from a

serial port. There are no message boundaries, the message splitup is at the whim of the

sender, the receiver, and every router in between, and never, ever think that a write of

8K bytes will be received in its entirety by a read of 8K bytes. Assume this is impossible

(in some rare networks it will happen, but not, for example, on Ethernet, where the

longest packet is 1456 bytes, so you will get chunks no larger than 1456-overhead bytes),

and Receive is free to return after any packet is received. Packets might be shorter,

depending on buffer issues, network technology between sender and receiver, and, of

course, short packets that are the end of the transmission.

joe



On Mon, 12 Jan 2004 18:04:45 -0800, "dev" <anonymous@discussions.microsoft.com>wrote:



Quote
Hi all,



I posted a message earlier regarding using CAsyncSocket

but the received messages are appended or chopped up. I

was suggested to use blocking sockets (by both this

newsgroup and outside this newsgroup) to solve this

problem, but the problem persisted.



What's wrong with my code? Is it doing blocking receive?

How come I still get incomplete messages?



Thanks!!



Here's my code:



#include "stdafx.h"

#include <winsock2.h>



int main(int argc, char* argv[])

{

int SOCK;

struct sockaddr_in pin;

struct timeval tv;

int port = 4;

int ret = SOCKET_ERROR;

char buf[7100];



WSADATA wsaData;

if (NO_ERROR != WSAStartup(MAKEWORD(2,2), &wsaData))

printf("Error at WSAStartup()\n");



pin.sin_family = AF_INET;

pin.sin_addr.s_addr = inet_addr( "1.2.3.4" );

pin.sin_port = htons(port);



SOCK = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);



printf("Connecting to server\n");

if ( connect(SOCK, (SOCKADDR*)&pin, sizeof(pin)) ==

SOCKET_ERROR)

{

printf( "Failed to connect. Error Code = %d\n",

WSAGetLastError() );

WSACleanup();

return -1;

}

printf("Connected.\n");



tv.tv_sec = 3000; setsockopt (SOCK, SOL_SOCKET,

SO_RCVTIMEO, (char*)&tv, sizeof(tv));



while ((0 != ret) || (WSAECONNRESET == ret))

{

if (WSAECONNRESET == WSAGetLastError())

break;



ret = recv(SOCK, buf, 7100, 0);

printf("here");

if ( ret == 0 || ret == WSAECONNRESET )

{

printf( "Connection Closed.\n");

break;

}

printf( "Bytes Recv: %ld\n", ret );

}



WSACleanup();



return 0;

}





The message that I posted earlier:

I am using CAsyncSocket with SOCK_STREAM option (using

TCP). I noticed that in most cases the messages I received

from the other end were ok, but sometimes two messages

were appended together, and sometimes a message was

chopped into two separate messages.



Is that a problem of using CAsyncSocket? Anyway I can fix

it? Do I get the same problem if I don't use CAsyncSocket?

Any suggestions?



Joseph M. Newcomer [MVP]

email: newcomer@flounder.com

Web: www.flounder.com">www.flounder.com

MVP Tips: www.flounder.com/mvp_tips.htm">www.flounder.com/mvp_tips.htm

-