469,287 Members | 2,600 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,287 developers. It's quick & easy.

Socket write behaviour is inconsistent?

I have a client and server that enjoy the following simple dialogue:

Client connects
Client sends request
Server sends response
Client disconnects

This is the way it must be. The response must be wrapped in a start
and end byte 0x02 and 0x03 resepctively.

suppose I have a byte[] response:

THIS FAILS:
socket.Send(new byte[]{ 0x02 }); //send start
socket.Send(response); //send start
socket.Send(new byte[]{ 0x03 }); //send start

it fails because the client throws an error that EOT was encountered
from the host
THIS WORKS:
byte[] tmp = new byte[response.Length + 2]
Array.Copy(response 0, tmp, 1);
tmp[0] = 0x02;
tmp[tmp.Length -2] = 0x03;
socket.send(tmp)
THIS WORKS:
List<ArraySegment<byte>tmp = new List<ArraySegment<byte>>();
tmp.Add(new ArraySegment<byte>(new byte[]{ 0x02 }));
tmp.Add(new ArraySegment<byte>(response));
tmp.Add(new ArraySegment<byte>(new byte[]{ 0x03 }));
socket.Send(tmp);
I enabled network tracing and in all cases the bytes written are the
same, same number of them, but the logs do look different in the first
case (3 calls to Send instead of jsut 1)

Can anyone shed any light on why these work any differently?

Nov 8 '07 #1
10 1884
On 2007-11-08 08:24:05 -0800, cjard <mc**@aber.ac.uksaid:
[...]
THIS WORKS:
byte[] tmp = new byte[response.Length + 2]
Array.Copy(response 0, tmp, 1);
tmp[0] = 0x02;
tmp[tmp.Length -2] = 0x03;
socket.send(tmp)
Is "tmp[tmp.Length -2]" a typo? Seems like that should be
"tmp[tmp.Length - 1]" instead.
[...]
I enabled network tracing and in all cases the bytes written are the
same, same number of them, but the logs do look different in the first
case (3 calls to Send instead of jsut 1)

Can anyone shed any light on why these work any differently?
You haven't posted enough code to answer definitively. For that
matter, you haven't really even described the behavior precisely enough
(on what statement exactly is the exception thrown?).

However, since normally it should not matter how you send the bytes
(that is, whether they are grouped in a single array or are sent one at
a time, or something in between), that suggests that either the
termination byte 0x03 is optional, or the data contained in the
"response" buffer already includes a termination byte.

Either would explain why the server might close the connection before
you get a chance to send that last byte.

If that's not it, then you should post a concise-but-complete sample of
code that reliably demonstrates the problem. Note that for networking
code, "complete" means both ends of the connection. The point of
"complete" is so that someone can actually run and test your code.

Pete

Nov 8 '07 #2
cjard <mc**@aber.ac.ukwrote:
I have a client and server that enjoy the following simple dialogue:

Client connects
Client sends request
Server sends response
Client disconnects

This is the way it must be. The response must be wrapped in a start
and end byte 0x02 and 0x03 resepctively.

suppose I have a byte[] response:

THIS FAILS:
socket.Send(new byte[]{ 0x02 }); //send start
socket.Send(response); //send start
socket.Send(new byte[]{ 0x03 }); //send start

it fails because the client throws an error that EOT was encountered
from the host
What does the client code look like? The above should work - it may end
up getting sent on separate packets, but the client should handle that.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Nov 9 '07 #3
Is "tmp[tmp.Length -2]" a typo? Seems like that should be
"tmp[tmp.Length - 1]" instead.
It is a typo, sorry

>
[...]
I enabled network tracing and in all cases the bytes written are the
same, same number of them, but the logs do look different in the first
case (3 calls to Send instead of jsut 1)
Can anyone shed any light on why these work any differently?

You haven't posted enough code to answer definitively.
I'd assert I have. The concept is that the following approaches ought
to be equivalent:

a) Send 1 byte, Send many bytes, Send 1 byte
b) copy 1 byte to buffer, copy many bytes to buffer, copy one byte to
buffer, send entire buffer
c) make a list of 3 ArraySegment<byte>

For that
matter, you haven't really even described the behavior precisely enough
(on what statement exactly is the exception thrown?).
There is no exception. The client device is a relatively dumb terminal
- a credit card terminal to be precise. When I interact with it in the
first way, it drops the conenction and contacts the server again, each
time spitting out a piece of paper saying "End of Transmission from
host"

Interact with it in the latter two ways and it works perfectly.
However, since normally it should not matter how you send the bytes
(that is, whether they are grouped in a single array or are sent one at
a time, or something in between), that suggests that either the
termination byte 0x03 is optional, or the data contained in the
"response" buffer already includes a termination byte.
The terminating 0x03 is mandatory, as far as the spec is concerned.
There is a device in between the terminal and the server in the form
of a terminating unit that connects the british X25 network, with the
local LAN, which could in theory add these bytes itself, but I doubt
that it does this, because attempting to send just the message buffer
without the requisite 0x02 / 0x03 fails.

Either would explain why the server might close the connection before
you get a chance to send that last byte.
The server isnt supposed to close the connection; the dumb client gets
(some of?) whatever I send, dumps the connection and retries. I find
out the connection was dropped because I return to Read() on a
blocking socket and some time later it unblocks having read 0 bytes

If that's not it, then you should post a concise-but-complete sample of
code that reliably demonstrates the problem. Note that for networking
code, "complete" means both ends of the connection. The point of
"complete" is so that someone can actually run and test your code.
Indeed, and I totally agree. THere is a small problem with this
though; If you have a spare credit card terminal, a connection to the
british X25 or a company that can arrange this, an ACP device to
provide the necessary X25 <TCP link then I'll gladly send some
working code. As it is, those things are usually pretty hard to come
by to run a quick test :(

Such is the difficulty of debugging the situation; all i know is that
sending piecemeal doesnt work, and sending in one go does. Indeed the
TCP-ness of the chain will only go as far as our ACP before it reverts
to X25. Most irritating.

Nov 9 '07 #4

What does the client code look like? The above should work - it may end
up getting sent on separate packets, but the client should handle that.
If I knew, I would have saved hours. Terminal manufacturers dont give
that sort of stuff up. :(
Nov 9 '07 #5
On 2007-11-09 08:47:01 -0800, cjard <mc**@aber.ac.uksaid:
[...]
You haven't posted enough code to answer definitively.

I'd assert I have.
That seems like a silly thing to assert. It's not really for you to say.
The concept is that the following approaches ought
to be equivalent:

a) Send 1 byte, Send many bytes, Send 1 byte
b) copy 1 byte to buffer, copy many bytes to buffer, copy one byte to
buffer, send entire buffer
c) make a list of 3 ArraySegment<byte>
Of course they should be equivalent. But obviously they are not. So
obviously there is something else going on.

By this time, there are now two strong pieces of evidence that you have
not posted enough code to answer your question definitively:

1) See above. The mere fact that your short description describes
something that _should_ work but doesn't means there's something
missing from the short description.

2) Has anyone provided you with a definitive answer based on the
information you've provided so far? No. So unless you think that
people are just ignoring your question for the heck of it, it's much
more likely there's a more fundamental reason for the lack of a
definitive answer: you haven't yet provided enough detail for one to be
given.

You can assert that you've provided enough information 'til the cows
come home, but as long as a person trying to answer the question tells
you that you haven't provided enough information, you haven't.
>For that
matter, you haven't really even described the behavior precisely enough
(on what statement exactly is the exception thrown?).

There is no exception. The client device is a relatively dumb terminal
- a credit card terminal to be precise. When I interact with it in the
first way, it drops the conenction and contacts the server again, each
time spitting out a piece of paper saying "End of Transmission from
host"
Then why did you write "the client throws an error"?

I have assumed in my reply that when you write "client" you are talking
about your own code and when you write "host" you are talking about the
remote endpoint for your connection.

If those are not the correct labels, you should clarify that, and you
should be VERY specific about what errors and other behaviors happen.
Your original post is very vague on those matters, and as with the lack
of actual code, it makes it very hard to answer the question without
better details.
Interact with it in the latter two ways and it works perfectly.
>However, since normally it should not matter how you send the bytes
(that is, whether they are grouped in a single array or are sent one at
a time, or something in between), that suggests that either the
termination byte 0x03 is optional, or the data contained in the
"response" buffer already includes a termination byte.

The terminating 0x03 is mandatory, as far as the spec is concerned.
No doubt that as far as the spec is concerned everything should work
fine as it is now.

But that's not really all that relevant, is it?
[...]
Either would explain why the server might close the connection before
>you get a chance to send that last byte.

The server isnt supposed to close the connection; the dumb client gets
(some of?) whatever I send, dumps the connection and retries. I find
out the connection was dropped because I return to Read() on a
blocking socket and some time later it unblocks having read 0 bytes
Again, I'm not really clear on who is "server" and who is "client"
here. When I write "server" in the above quote, I'm talking about the
remote endpoint of your connection, because you _appeared_ to write
"client" to describe your own code. But if that's not right, you
should clarify.

Your original post implies that the remote endpoint is closing the
connection. Is that what is happening? If not, please explain in
detail what is actually happening.

[...]
>If that's not it, then you should post a concise-but-complete sample of
code that reliably demonstrates the problem. Note that for networking
code, "complete" means both ends of the connection. The point of
"complete" is so that someone can actually run and test your code.

Indeed, and I totally agree. THere is a small problem with this
though; If you have a spare credit card terminal, a connection to the
british X25 or a company that can arrange this, an ACP device to
provide the necessary X25 <TCP link then I'll gladly send some
working code. As it is, those things are usually pretty hard to come
by to run a quick test :(

Such is the difficulty of debugging the situation; all i know is that
sending piecemeal doesnt work, and sending in one go does. Indeed the
TCP-ness of the chain will only go as far as our ACP before it reverts
to X25. Most irritating.
Well, you left out that part of the situation in your original post. I
think it's entirely possible that the issue you're running into has
absolutely nothing to do with .NET (and certainly not to do with C#),
and everything to do with the fact that your supposed TCP connection
traverses a network segment that isn't TCP at all.

If it _is_ in fact an issue specific to .NET, then you would not need
the specific hardware. You would be able to write a small test
application that acts as the specific hardware does, for the purpose of
providing test code to work with.

If you cannot reproduce the problem without this foreign hardware, then
that strongly suggests that you either need to simply accomodate the
needs of that hardware, or take up the issue with those who maintain or
distribute the hardware.

If you still feel that your question is an appropriate .NET question,
you need to provide more details as I've described.

Pete

Nov 9 '07 #6
The concept is that the following approaches ought
to be equivalent:
a) Send 1 byte, Send many bytes, Send 1 byte
b) copy 1 byte to buffer, copy many bytes to buffer, copy one byte to
buffer, send entire buffer
c) make a list of 3 ArraySegment<byte>

Of course they should be equivalent. But obviously they are not. So
obviously there is something else going on.
Your opinion of their suggested equivalence is appreciated, thankyou.

By this time, there are now two strong pieces of evidence that you have
not posted enough code to answer your question definitively:
And my assertion that I have, still stands. I could post the entire
program, but the only variation you will see is in the lines given. As
they are the only variance, I am seeking opinions or explanations of
any apparent or known difference.

1) See above. The mere fact that your short description describes
something that _should_ work but doesn't means there's something
missing from the short description.
I disagree. I'm not here to debate the semantics of this. I have
posted 3 sections of code, two that work and one that does not, with
the assertion that their behaviour in a goal oriented sense, ought to
be equivalent. The behaviour is not equivalent, because the results
observed differ.

2) Has anyone provided you with a definitive answer based on the
information you've provided so far?
There are several possible scenarios beyond your answer to your own
rhetoric. In summary, most people reading the question either do not
know the answer, or cannot be bothered to explain it. I usually demand
a level of precision from others when they ask a question that I know
the answer to, but feel that they have not sifficiently helped
themselves through their own clarity of thought in producing an
understandable description of the problem. If you feel this to be the
case here (to whit; you know the answer but youre taking the same
stance that I take in being bloody minded about the specification of
the question, for my own good), do let me know, wont you? :)

people are just ignoring your question for the heck of it
While I dont mean to sound big headed, it's rare that I ask a
question, not because I know everything, but usually because I can
easily take a correct guess or research something I dont know.
Occasionally, when I find the topic particularly hard to research or
exceptionally unusual, I'll defer to other sources such as people more
knowledgeable than myself. As these situations are invariably few and
far between, and those questions often go unanswered, I'm left with
one of two conclusions; I'm crap at asking questions, or noone knows/
cares to give the answer.

You can assert that you've provided enough information 'til the cows
come home, but as long as a person trying to answer the question tells
you that you haven't provided enough information, you haven't.
Hmm.. Well, we can run with that, and I'll answer your probes for more
info as far as I am able. There are limitations to what I can discover
here, which I dont doubt may lead us to an impasse; I wont be able to
provide information you assert to be essential to answering the
question. Ergo, the question shall have no answer.

There is no exception. The client device is a relatively dumb terminal
- a credit card terminal to be precise. When I interact with it in the
first way, it drops the conenction and contacts the server again, each
time spitting out a piece of paper saying "End of Transmission from
host"

Then why did you write "the client throws an error"?
I'll concede that choosing the word "throws" was poor; in .NET terms
it would have led you to believe the client app was something under
source code control

find: throws
replace: reports

I have assumed in my reply that when you write "client" you are talking
about your own code and when you write "host" you are talking about the
remote endpoint for your connection.
I wrote the host, the client is a dumb terminal running software
developed by Sagem

If those are not the correct labels, you should clarify that, and you
should be VERY specific about what errors and other behaviors happen.
Your original post is very vague on those matters, and as with the lack
of actual code, it makes it very hard to answer the question without
better details.
Considering the bi-directionality of TCP communication, I'm not sure
that the specifics on the client and server really matter, but i did
point out the desired dialog flow at the start of the post.. Here is
what goes on:

The terminal collects transaction information from user interaction
and makes a dialup conenction over GPRS, to O2. O2 route the
connection to BT's Cardway X25 PAD. From there the conenction is
routed via some proprietary protocol we know (nor care) anything about
terminating in a device attached to one of the ISDN lines entering the
building. The device has a connection to the LAN and forges a
connection to the host software I wrote, on a specific port. I read
the request, calcualte some things and response with a few bytes.

When the response is sent using the first chunk of code, the terminal
gives up, announces that we sent it an EOT (we didnt) and redials.
When corresponding in the latter two ways, the terminal is satisfied
with the response it receives, drops the connection and we dont hear
from it again
The terminating 0x03 is mandatory, as far as the spec is concerned.

No doubt that as far as the spec is concerned everything should work
fine as it is now.
I dont really understand this sentence. It apears to be missing some
punctuation.

But that's not really all that relevant, is it?
The spec is relevant; the terminal is asserted to be compliant with
the spec, and I really dont think a couple of people chewing over a
puzzle on Usenet can question every major bank in the UK at this
stage.

Again, I'm not really clear on who is "server" and who is "client"
here. When I write "server" in the above quote, I'm talking about the
remote endpoint of your connection, because you _appeared_ to write
"client" to describe your own code. But if that's not right, you
should clarify.
Hm. OK, few definitions:
Client: the submitter of a Request, a credit card terminal with a
software written by a third party
Server/Host: the respondant to the Request, the issuer of the
Response, a piece of .NET code written by myself

Your original post implies that the remote endpoint is closing the
connection. Is that what is happening? If not, please explain in
detail what is actually happening.
The spec states that the recipient of the last message in a dialogue
should close the connection. In all cases as far as I am concerned, I
send a response. I only find out if it is satisfactory or not when the
client re-presents itself (or not)

If the client goes away and is not heard from again ,for this request,
then it was satisfied

When sending the response piecemeal, the client returns. When
buffering the whole response ina byte[] or List and then sending it,
the client does not return. The diiagnostic codes printed by the
client when it retries, indicate that it received an EOT from the
server host. EOT is defined as 0x04, not that it matters; No such byte
is ever sent by the host and EOT is taken to mean that the
transmission was ended.

If you still feel that your question is an appropriate .NET question,
you need to provide more details as I've described.
You touched on the source of my puzzlement in that I have to work
around an issue. Your opinion that the three methods ought be
equivalent was most useful; i concur and I have no explanation for why
I should have to "work round" in this way, or even why sucha "work
round" works at all. If all three methods are functionally equivalent,
why does one fail?

Nov 10 '07 #7
On 2007-11-09 17:07:10 -0800, cjard <mc**@aber.ac.uksaid:
[...]
2) Has anyone provided you with a definitive answer based on the
information you've provided so far?

There are several possible scenarios beyond your answer to your own
rhetoric. In summary, most people reading the question either do not
know the answer, or cannot be bothered to explain it.
Interesting that you don't consider the possibility that the question
was simply not presented well enough for a person with the answer to
provide that answer.
[...]
I usually demand
a level of precision from others when they ask a question that I know
the answer to, but feel that they have not sifficiently helped
themselves through their own clarity of thought in producing an
understandable description of the problem. If you feel this to be the
case here (to whit; you know the answer but youre taking the same
stance that I take in being bloody minded about the specification of
the question, for my own good), do let me know, wont you? :)
It's not the case at all. Generally, when I feel a person hasn't
sufficiently helped themselves, I just ignore them. I would never
waste time just trailing them along if I know the answer myself.

And given your elaborations, I am beginning to suspect you will not
find the answer here at all, because I suspect the problem has
absolutely nothing to do with .NET. The behavior you're describing
just isn't the sort of thing that .NET might affect, but it certainly
is the kind of thing that mixing and matching different network
transports might, or some sort of problem with the client terminal
might cause.

Thus, I suspect the latter possibilities over something related to the
..NET implementation of the host.

I definitely do not know the answer to your question as stated, but
even as things stand now I have no way to know if that's because the
problem has nothing to do with .NET, or because you simply haven't
provided enough details.

I do know that there's no way to tell the difference for sure until you
do provide more details.
[...]
>>The terminating 0x03 is mandatory, as far as the spec is concerned.

No doubt that as far as the spec is concerned everything should work
fine as it is now.

I dont really understand this sentence. It apears to be missing some
punctuation.
My point is that given the information you've provided about the spec,
everything should work fine.
>But that's not really all that relevant, is it?

The spec is relevant; the terminal is asserted to be compliant with
the spec, and I really dont think a couple of people chewing over a
puzzle on Usenet can question every major bank in the UK at this
stage.
Given that everything does not work fine, then obviously some component
in your system is not complying with the spec. Thus, the fact the spec
suggests everything should work fine is not at all relevant.

The spec itself is relevant, of course. But the fact that the spec
says everything should work fine is irrelevant (or rather, it's
redundant...by definition, when things comply with a spec, everything
works fine so of course a spec would say everything should work fine).
[...]
>If you still feel that your question is an appropriate .NET question,
you need to provide more details as I've described.

You touched on the source of my puzzlement in that I have to work
around an issue. Your opinion that the three methods ought be
equivalent was most useful; i concur and I have no explanation for why
I should have to "work round" in this way, or even why sucha "work
round" works at all. If all three methods are functionally equivalent,
why does one fail?
There's no way to answer that question definitively without a
concise-but-complete sample of code that reliably demonstrates the
problem.

If you cannot create such an example of code using only C#/.NET, then
it stands to reason that the problem does not lie within .NET and thus
your question cannot be answered here. In that case, it's likely a
problem with some other component in your network system. Even if that
system works perfectly with some other implementation of the host, all
that would mean is that that particular host has worked around the
problem (accidently or on purpose, presumably in a manner similar to
the method you've already found).

On the other hand, if you _can_ reproduce the problem using only
C#/.NET, then if you post the concise-but-complete sample of code that
does that, it is _much_ more likely that someone here can answer the
question.

But absent that sample, this is the wrong place for you to seek an answer.

Pete

Nov 10 '07 #8
In article <11*********************@50g2000hsm.googlegroups.c om>, Cjard
wrote:
Such is the difficulty of debugging the situation; all i know is that
sending piecemeal doesnt work, and sending in one go does. Indeed the
TCP-ness of the chain will only go as far as our ACP before it reverts
to X25. Most irritating.
Have you tried any kind of a protocol analyzer? Something like
Ethereal/Wireshark in the TCP environments and maybe a hardware one in
the X.25 environment. (It sounds as if both ends are TCP/IP with an
intervening X.25 network).

You can then compare the data at both ends. Is the intervening X.25
portion native X.25 or does it perhaps use something like an x.3 PAD? I
can readily imagine the data being packetized differently in your two
scenarios. As X.25 doesn't inherently present the same byte stream
service that TCP does, it would seem easy to have different assumptions
about handling packets. (A very common beginner problem with TCP socket
programming is, in fact, not reassembling data data that arrives in
multiple chunks instead of in a single larger chunk)

If there's a PAD involved, you're using the kind of characters that PADs
often use in deciding when to send data.

Hope this helps

Mike
Nov 10 '07 #9
cjard <mc**@aber.ac.ukwrites:
[...]
THIS FAILS:
socket.Send(new byte[]{ 0x02 }); //send start
socket.Send(response); //send start
socket.Send(new byte[]{ 0x03 }); //send start

it fails because the client throws an error that EOT was encountered
from the host
THIS WORKS:
byte[] tmp = new byte[response.Length + 2]
Array.Copy(response 0, tmp, 1);
tmp[0] = 0x02;
tmp[tmp.Length -2] = 0x03;
socket.send(tmp)
[...]

As others have suggested, look at this with a packet sniffer.

A common bug in C socket programming is something like this:

char buf[8192];
read(socket_fd, buf, 8192);
if (!strchr(buf,'\x03')) {
/* Error! */
}

If three different packets are sent, read() can return 3 times, each
time with part of the packet.

It's possible that the first example sends 3 different packets, and
the second sends just one. In that case, the first example would
expose this bug, while the second would work around it (or mask it,
depending on your viewpoint).

One possibility is to make sure Nagle's algorithm is enabled (that is,
the NODELAY option is turned off) on the sending socket. This may
combine the multiple Send's into one, although it's not guaranteed.
Another possibility is to just use one of the two examples that works.
:-)

Good luck!

----Scott.
Nov 12 '07 #10
On 2007-11-11 21:26:05 -0800, Scott Gifford <sg******@suspectclass.comsaid:
[...]
If three different packets are sent, read() can return 3 times, each
time with part of the packet.
Well, to be more specific: read() can return 3 times (or any other
number of times, up to the total number of bytes in the transmission),
each time with part of the "packet" (inasmuch as you can even talk
about a "packet" in the context of a TCP stream), no matter how many
different "packets" are sent.

TCP makes no guarantees at all with respect to a correlation between
byte grouping in sent data and byte grouping in received data.

Pete

Nov 12 '07 #11

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

7 posts views Thread by Nathan Davis | last post: by
4 posts views Thread by Bryan Olson | last post: by
reply views Thread by Bernhard Schmidt | last post: by
10 posts views Thread by Sheila King | last post: by
8 posts views Thread by Dinsdale | last post: by
7 posts views Thread by semedao | last post: by
9 posts views Thread by Irmen de Jong | last post: by
11 posts views Thread by atlaste | last post: by
1 post views Thread by CARIGAR | last post: by
reply views Thread by suresh191 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.