C# socket programming

K

kuba bogaczewicz

Hello all,
for my school project I have to write a small peer-2-peer application
using Sockets, and I've chosen C# for the task.
I've been doing some research on the topic, and I would really
appreciate if someone checked if I got all things right.

I am going to use asynchronous connections, and here comes some of my
doubts:
-> I want to send each message in a scheme: 4 bytes with the size, then
actual message. According to MSDN I got with VS2003
BeginSend()/EndSend() and BeginReceive/EndReceive will block (in it's
own thread) until the desired amount of data is sent or received. But
I've seen in 'C# Network Programming', that the proper method of
sending would be in a loop checking how much data had been sent, and
resending what is left. Can I trust MSDN on this one - it will be
rather painful to do loop-sending with asynchronous methods, while
having
receive 4 bytes;
receive actual message;
will be quite easy.

-> does BeginSend() puts byte[] with data in some other system queue?
This question is rather essencial to me, because on one Socket
connection I will be sending possibly a couple of files, and also the
same Socket will have to be able to send 'search messages'. Each file
will be sent one part after another, no flooding socket. But durign
that sending user might want to send a 'search' message, and I will
have to do BeginSend() for this one. Can this somehow mess with byte
order sent through the socket?
if on the other side on the connetion application is constantly doing
BeginRecive;
EndReceive;
can this be making problems with buffors on any side?

I'd greatly appreciate quick responses,
thank you in advance

Kuba Bogaczewicz
 
N

Nicholas Paldino [.NET/C# MVP]

Kuba,

I think you are mistaken about how the async Send and Receive messages
work.

If you call BeginReceive, passing a length of 4, the callback (or
waiting on AsyncWaitHandle) will not return until four bytes have been read,
or some other error occurs.

If you did this asynchronously, you would have one callback for reading
the four bytes. At the end of that callback, you would issue the request
for the bytes in the message (the length of which you now know), and pass it
a callback which would process the message once those bytes are read.

If you only want to read chunks of the message at a time, then you would
have to reissue the call to BeginReceive, and store the bytes that are read
somewhere, until you have enough to process.

Hope this helps.
 
K

kuba bogaczewicz

Nicholas said:
Kuba,

I think you are mistaken about how the async Send and Receive messages
work.

If you call BeginReceive, passing a length of 4, the callback (or
waiting on AsyncWaitHandle) will not return until four bytes have been read,
or some other error occurs.

Thank you for that information. That was how I did program it
eventually, but since I'm testing it using localhost, I did not know if
that thing about receiving all or nothing was true.
If you did this asynchronously, you would have one callback for reading
the four bytes. At the end of that callback, you would issue the request
for the bytes in the message (the length of which you now know), and pass it
a callback which would process the message once those bytes are read.
(...)

And it's done that way and it's working :) I'm always interested in
reading whole messages.

Thank you for reply

Kuba Bogaczewicz
 
K

kuba bogaczewicz

kuba said:
Hello all,
for my school project I have to write a small peer-2-peer application
using Sockets, and I've chosen C# for the task.
I've been doing some research on the topic, and I would really
appreciate if someone checked if I got all things right.

I am going to use asynchronous connections, and here comes some of my
doubts:
-> I want to send each message in a scheme: 4 bytes with the size, then
actual message. According to MSDN I got with VS2003
BeginSend()/EndSend() and BeginReceive/EndReceive will block (in it's
own thread) until the desired amount of data is sent or received. But
I've seen in 'C# Network Programming', that the proper method of
sending would be in a loop checking how much data had been sent, and
resending what is left. Can I trust MSDN on this one - it will be
rather painful to do loop-sending with asynchronous methods, while
having
receive 4 bytes;
receive actual message;
will be quite easy.

partially true. BeginSend as well as Send will always either send the
amount of data that is desired or end with an exception.
But Receive and BeginReceive reads 'as much data as is available, up to
the number of bytes specified by the size parameter.'
buu on me, that I found that that late....
and thank god I was testing it with virtual machines :)
responding to myself is not my hobby, just sending it for next
generations, who will have to same question :)

kuba bogaczewicz
 
S

Sami Vaaraniemi

Nicholas Paldino said:
Kuba,

I think you are mistaken about how the async Send and Receive messages
work.

If you call BeginReceive, passing a length of 4, the callback (or
waiting on AsyncWaitHandle) will not return until four bytes have been
read, or some other error occurs.

This is a common misconception about sockets. In the docs it says:

<quote>
If you are using a connection-oriented Socket, the BeginReceive method will
read as much data as is available, up to the number of bytes specified by
the size parameter.
</quote>

This means that if you pass a length of 4, then it can return anything *up
to* 4 bytes. So in theory, it could return e.g., 2 bytes. In this case
you'll need to call BeginReceive again, this time passing a length of 2 if
you are expecting to receive a total of 4 bytes.

Same logic applies to synchronous Receive.

Regards,
Sami
 
H

Helge Jensen

Nicholas said:
I think you are mistaken about how the async Send and Receive messages
work.

If you call BeginReceive, passing a length of 4, the callback (or
waiting on AsyncWaitHandle) will not return until four bytes have been read,
or some other error occurs.

Are you sure about that? The progeam below demonstrates a different
behaviour: that BeginReceive does just like Read: returns the number of
bytes read and 0 for end-of-stream.

====> Testprogram <=====

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections;

class Class1
{
static int sendCount = 0;
static int sendMax = 10;
static byte[] sendBuf = new byte[50];
static byte[] readBuf = new byte[100];
static public void Received(IAsyncResult result)
{
Stream s = (Stream)result.AsyncState;
int read;
try
{
read = s.EndRead(result);
}
catch
{
s.Close();
throw;
}
Console.WriteLine("read: {0}", read);
if ( read == 0 ) // End of stream
s.Close();
else
s.BeginRead(readBuf, 0, readBuf.Length, new
AsyncCallback(Received), s);
}
static public void Sent(IAsyncResult result)
{
TimeSpan waitAmount = TimeSpan.FromSeconds(.1);
Thread.Sleep(waitAmount);
Stream s = (Stream)result.AsyncState;
if ( sendCount < sendMax )
s.BeginWrite(sendBuf, 0, sendBuf.Length, new AsyncCallback(Sent), s);
else
s.Close();
sendCount++;
}
static public void Accept(IAsyncResult result)
{
Socket s = (Socket)result.AsyncState;
Socket connection;
try
{
connection = s.EndAccept(result);
}
catch
{
s.Close();
throw;
}
NetworkStream conncetion_stream = new NetworkStream(connection, true);
conncetion_stream.BeginRead(readBuf, 0, readBuf.Length, new
AsyncCallback(Received), conncetion_stream);
}
[STAThread]
static void Main(string[] args)
{
IPEndPoint receiver_ep = new IPEndPoint(IPAddress.Loopback, 10000 +
new Random().Next() % 1000);
Socket receiver_socket = new
Socket(receiver_ep.Address.AddressFamily, SocketType.Stream,
ProtocolType.Tcp);
receiver_socket.Bind(receiver_ep);
receiver_socket.Listen(100);
receiver_socket.BeginAccept(new AsyncCallback(Accept),
receiver_socket);

IPEndPoint sender_ep = new IPEndPoint(IPAddress.Loopback,
receiver_ep.Port+1);
Socket sender_socket = new Socket(sender_ep.Address.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
sender_socket.Bind(sender_ep);
sender_socket.Connect(receiver_ep);
Stream sender_stream = new NetworkStream(sender_socket, true);
sender_stream.BeginWrite(sendBuf, 0, sendBuf.Length, new
AsyncCallback(Sent), sender_stream);

while ( sendCount < sendMax )
{
Thread.Sleep(TimeSpan.FromSeconds(1.0));
}
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top