Client-Server application (based on sockets) - too many messages at the same time

  • Thread starter Thread starter Cichy
  • Start date Start date
C

Cichy

Hello,

I'm writing a Client-Server application using sockets (asynchronous).
There is a Server (Master) which accepts incoming connections, and
Client (Slave).
Afetr establishing connections with all Slaves I wanna hit a button
"Automatic", then everything must be reorganised, there is an
ellection for a new Master.
Everything is all right when I'm connecting manually (when I hit a
button connect), but after hitting this button (Automatic) it looks
like there is to many connections at the same time :/

When a Slave is connecting he's sending a Login command, Master is
responding to him with a unique number for him (his name). It looks
like all of them are sent, but they are not reaching the slaves.

I'm new in C# and I think that I'm doing something wrong. Maybe there
is some special way for mantaining many request at the same time.

Here are the most important fragments of my code:


Form1.cs:

private void btnAutomatic_Click(object sender, EventArgs e)
{
//We're flushing the info about CPU speed's of each
connected slave
//We're sending the Ellection Command to each connected
Slave
Data msgToSend = new Data();
byte[] message;
msgToSend.cmdCommand = Command.Ellection;
message = msgToSend.ToByte();
lock (_master.__clientList)
{
foreach (ClientInfo client in _master.__clientList)
{
if (client.type == 1)
{
client.cpuSpeed = 0;
client.socket.BeginSend(message, 0,
message.Length, SocketFlags.None, new AsyncCallback(_master.OnSend),
client.socket);
}
}
}
}



- Master.cs:

private void OnReceive(IAsyncResult ar)
{
lock (__clientList)
{
try
{
Socket clientSocket = (Socket)ar.AsyncState;
clientSocket.EndReceive(ar);

//Transform the array of bytes received from the
user into an intelligent form of object Data
Data msgReceived = new Data(byteData);

//We will send this object in response the users
request
Data msgToSend = new Data();

byte[] message;


msgToSend.cmdCommand = msgReceived.cmdCommand;
msgToSend.strName = msgReceived.strName;


mainForm.messageReceived(msgReceived.strName,
Convert.ToString(msgReceived.cmdCommand), msgReceived.strMessage);



switch (msgReceived.cmdCommand)
{
case Command.Login:
//When a user logs in to the server then
we're adding him to our list of clients
ClientInfo clientInfo = new ClientInfo();
clientInfo.socket = clientSocket;

//Set an unique name (number) for every
connected client
if (_clientList.Count == 0)
clientInfo.nr = 0;
else
{
foreach (ClientInfo client in
__clientList)
{
if (clientInfo.nr <=
client.nr)
clientInfo.nr = client.nr
+ 1;
}
}
clientInfo.strName = msgReceived.strName +
clientInfo.nr;

if (msgReceived.strName == "slave")
clientInfo.type = 1;
else
clientInfo.type = 2;

_clientList.Add(clientInfo);

//Set the text of the message which will
be send to user who just logged into our server
msgToSend.strMessage = "Your name is: ";
msgToSend.strName =
clientInfo.nr.ToString();



mainForm.messageReceived(msgToSend.strName,
Convert.ToString(msgToSend.cmdCommand), "He's name is: ");


message = msgToSend.ToByte();
clientInfo.socket.BeginSend(message, 0,
message.Length, SocketFlags.None, new AsyncCallback(OnSend),
clientInfo.socket);


mainForm.newClientConnected(clientInfo.strName);
break;



- Slave.cs:

private void OnReceive(IAsyncResult ar)
{
try
{
clientSocket.EndReceive(ar);
Data msgReceived = new Data(byteData);
Data msgToSend = new Data();
byte[] b;


mainForm.messageReceived(msgReceived.strName,
Convert.ToString(msgReceived.cmdCommand), msgReceived.strMessage);


//Process the message received
switch (msgReceived.cmdCommand)
{
case Command.Login:
nr = Convert.ToInt32(msgReceived.strName);
strName = "slave" + nr.ToString();
mainForm.setTitle(strName);

break;



Thank you very much for all issues and ideas.
P.S. Sorry for my english.

Lukas
 
[...]
Everything is all right when I'm connecting manually (when I hit a
button connect), but after hitting this button (Automatic) it looks
like there is to many connections at the same time :/

When a Slave is connecting he's sending a Login command, Master is
responding to him with a unique number for him (his name). It looks
like all of them are sent, but they are not reaching the slaves.

I'm new in C# and I think that I'm doing something wrong. Maybe there
is some special way for mantaining many request at the same time.

#1 problem I see in your code is that you don't do anything to check the
number of bytes sent *or* received to ensure that you have a full
"message". Because you write about "connections" I am assuming that you
are using a connection-oriented protocol. That is, TCP. TCP does not
guarantee anything except that the bytes that are received are exactly in
the same order in which they were sent. They may be grouped in entirely
arbitrary ways; you can receive a single byte at a time, or (as is more
common, especially when dealing with "messages" that are relatively small)
you can receive more bytes at once than were sent at once (that is,
multiple sends are combined into a single receive).

That's the receiving side of things, and is the most common error.
However, the same issue exists with respect to sending. You need to check
the count of bytes returned when the send completes to find out how many
bytes *actually* were sent. If fewer bytes were sent than the number you
tried to send, you need to reattempt the send, starting with the first
byte that *wasn't* sent (so index into the original buffer you tried to
send by the number of bytes that were sent, and send the rest of the data
from that point).

Other than that, I don't see anything glaringly wrong with the code you
posted, so I think there's a good chance that a) you are capable of fixing
the above problems without too much trouble (not everyone ought to be
writing networking code, but I'm not hearing alarm bells seeing your code
:) ) and b) that when you do fix those problems, you'll find that your
communications are every bit as reliable as you might hope. :)

If it turns out that you are using UDP, then you have a different problem:
first, UDP doesn't have the concept of "connections" (even though you can
"connect" a UDP socket, that's really just a shorthand way of specifying
the default remote endpoint) and second, UDP isn't reliable (datagrams
sent may go unreceived, they may arrive more than once, and they may
arrive out of order).

Hope that helps.

Pete
 
Thank you for response Pete.

Yes, You we're right that I'm using TCP Protocol. I thought that when
I'm sending some datas over a socket it's checking how many bytes
we're sent and received.
I really was sure that there is some sort of byte (like EOM - End Of
Message, like EOF in files) which idnicates if everything was sent.

But know I'm not too sure where should I check this things?
When sending it looks more simple, I have a method:

public void OnSend(IAsyncResult ar)
{
try
{
Socket client = (Socket)ar.AsyncState;
client.EndSend(ar);
}
catch (Exception ex)
{
if (eerrorOccured != null)
eerrorOccured(this, ex.Message);
}
}

and probably here i can check how many bytes where sent (probably I
have to add second parameter with message to be able to resend some
bytes).
But where should I check if i received all bytes (and the more
important questions, how could I know how many of them should
be ???).


And also, is this construction doesn't fix the problem of receiving
only a part of a message:

clientSocket.EndReceive(ar);


Thank you for very much your help.
Best wishes,

Lukas
 
Ohh, and also I forgot to mention that sometimes my application
behaves in a strange way.
When I hit the "Automatic" button I'm receiving an error saying:

"demand of sending or receiving data was blocked, because socket is
not connected (and during sending over a socket datas when using "send
to" there is no address given"

And when I hit OK the message is delivered to this specific Slave.
(???) (He receives a message with his unique number given to him by
Master).

I really don't know why sometimes it behaves fine (altough there is a
exception like above) and usually there is no problem like that, but
no messages a delivered.


Thanks.
Lukas
 
Ohh, and also I forgot to mention that sometimes my application
behaves in a strange way.
When I hit the "Automatic" button I'm receiving an error saying:

"demand of sending or receiving data was blocked, because socket is
not connected (and during sending over a socket datas when using "send
to" there is no address given"

I have to assume that text is the Message property of an Exception that is
generated, and that the text you've provided here is a translation of an
actual error message that is originally in some language other than
English. Is that correct? Because the text sure doesn't read the way I'm
used to seeing messages from .NET.
And when I hit OK the message is delivered to this specific Slave.
(???) (He receives a message with his unique number given to him by
Master).

Is the socket still connected after the exception? That is, do any sends
*after* the exception succeed?

It's not really all that unusual for an error for a given send to occur,
but for the data to still get through. In TCP, part of having a
successful send is that the data is acknowledged. Likewise, if an error
occurs, there's no guarantee that the data *didn't* get through. All you
know is that the complete "send/ack" process wasn't successful.

However, once you get an error on the socket, I would expect *future*
attempts at i/o to not work (depending on the error, of course...but the
one you're describing sure sounds fatal).

Pete
 
Yes, You we're right that I'm using TCP Protocol. I thought that when
I'm sending some datas over a socket it's checking how many bytes
we're sent and received.

Define "checking". In one sense, I suppose it is...after all, assuming
nothing's wrong with the connection, the bytes all do eventually get sent
and received. The "how many" is "checked" in that sense.

However, TCP doesn't do anything to ensure that between the first byte
sent and the last byte sent, that everything received is grouped exactly
the same way that it was sent.
I really was sure that there is some sort of byte (like EOM - End Of
Message, like EOF in files) which idnicates if everything was sent.

There's definitely nothing like that. You put a byte in at one end, that
byte comes out at the other. Nothing more, nothing less.
But know I'm not too sure where should I check this things?

You need to look at the return value for Socket.EndReceive() and
Socket.EndSend(). These are integers that tell you how many bytes were
actually successfully received or sent.
When sending it looks more simple, I have a method:

public void OnSend(IAsyncResult ar)
{
try
{
Socket client = (Socket)ar.AsyncState;
client.EndSend(ar);
}
catch (Exception ex)
{
if (eerrorOccured != null)
eerrorOccured(this, ex.Message);
}
}

and probably here i can check how many bytes where sent (probably I
have to add second parameter with message to be able to resend some
bytes).

You need to hang on to the original send buffer, presumably in some
per-client data structure. Along with that, you need to keep track of how
many bytes in the buffer have already been sent, so that when you call
Socket.EndSend(), you can compare the byte count with how many you had
left to send, and if the sent bytes are fewer than the amount you actually
have to send, make another attempt to send the remaining bytes.
But where should I check if i received all bytes (and the more
important questions, how could I know how many of them should
be ???).

Yes, that is the more important question. Your protocol needs to definea
way for the recipient of the data to know how large that data is, so that
it can tell whether it's received it all or not. How this is done depends
entirely on the protocol.

Some precede the data with a byte count (which itself has a predefined way
to know its length, whether that's because it's a fixed-size variable, or
the byte count is sent as a string, or something like that). Some rely on
something specific about the data itself; for example, strings that are
always null-terminated. Some use fixed-sized structures so that every
"message" is always the same size. And some even only allow for a single
"message" to be sent on a given connection; once a complete "message" has
been sent, the connection is closed (I'm not suggesting this is
appropriate for your design...just that it's an example of how some other
protocols work).

What you will do is entirely up to you, assuming you have defined your own
application-level protocol (which it appears you have). But you do need
to include something in your protocol so that the recipient knows when it
has received a complete "message".
And also, is this construction doesn't fix the problem of receiving
only a part of a message:

clientSocket.EndReceive(ar);

I'm sorry, I don't understand the above sentence.

Pete
 

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

Back
Top