[Mono-devel-list] UDP 40%+ loss
marcusmonaghan at f2s.com
marcusmonaghan at f2s.com
Mon Apr 4 12:03:52 EDT 2005
Thanks for the reply Jason.
I didn't post code initially as I was just seeing if there was a "ah yes, we
know about that one" answer.
So as there doesn't seem to be that, here is the code snippets. I have exluded
obtaining settings:
C code:
while (TRUE) /* receive (and pass on) loop */
{
/* Now clear buffers ready for next iteration */
memset(buffer, '\0', BUFLEN);
memset(outbuf, '\0', BUFLEN);
/* Let select know which file descriptor we want to wait on */
FD_SET(multicast_socket, &read_set);
/* If we are not using a file then add the tcp socket to the set */
if (message_file <= FAILURE) FD_SET(tcp_socket, &read_set);
/* Select needs to know the maximum file descriptor to look for. We
could specify FS_SETSIZE which is defined as 256 but
this would meen the kernal would be checking for extra file
descriptors that did not exist. */
if (multicast_socket > tcp_socket || message_file >= VALID)
max_fd = multicast_socket + 1;
else
max_fd = tcp_socket + 1;
/* Now select and wait for a signal */
now_msg(0, "Waiting on select ...\n", errno);
selected_fd = select(max_fd, &read_set, NULL, NULL, NULL);
now_msg(1, "After select ...\n", errno);
/* We have a connection so reset the connection_try indicator */
connection_try=0;
if (selected_fd == FAILURE)
{
now_msg_err(0, errno, "Error on select");
break;
}
if (selected_fd == TIMEOUT)
{
/* Currently this isn't supported so shouldn't be called yet */
now_msg(0, "Select timed out ... POLL");
/* Need to clear here as we are resetting at the top of the loop
*/
FD_CLR(multicast_socket, &read_set);
FD_CLR(tcp_socket, &read_set);
continue;
}
if ((message_file <= FAILURE) && FD_ISSET(tcp_socket, &read_set))
/* Data available on tcp socket, only if not using a file */
{
.. Doesn't fire!!!
} /* End of data available on TCP socket */
if (FD_ISSET(multicast_socket, &read_set)) /* Data available on udp
socket */
{
bytes_received=recvfrom(multicast_socket, buffer, BUFLEN, 0,
NULL, NULL); /* get one message at a time (as it is UDP) */
if(bytes_received==FAILURE)
{
now_msg_err(0, errno, "Error receiving multicast messages");
break;
}
/* Let the user know what we have received (remove a linefeed if
one is already there due to testing) */
if (buffer[bytes_received - 1] == '\n')
{
now_msg(5, "removing LF from input\n");
buffer[--bytes_received] = 0;
}
now_msg(0, "<<<[%d][%s]\n", bytes_received, buffer);
if (add_ascii_header == TRUE)
{
.. No longer used
}
else
{
sprintf(outbuf, "\"%s\"\n", buffer);
}
bytes_to_send = strlen(outbuf);
/* Depending on whether or not a file has been specified send to
to a tcp server or write it to a file */
if (message_file >= VALID) /* File provided */
{
now_msg(5, "Writing to file [%d]\n", bytes_to_send);
bytes_sent=write(message_file, outbuf, bytes_to_send);
}
else
{
now_msg(5, "Writing to socket [%d]\n", bytes_to_send);
bytes_sent=send(tcp_socket, outbuf, bytes_to_send, 0 ); /*
write the message - 0 = no options */
}
outbuf[bytes_to_send] = 0; /* for the record, remove the \n, but
retain real length for checking purposes */
now_msg(0, ">>>[%d][%s]\n", bytes_sent, outbuf);
} /* End of data available on udp socket */
} /* listener failed */
c# Code
public class MulticastClient
{
#region Member Variables
private string _multicastAddress = string.Empty;
private int _multicastPort = 0;
#endregion Member Variables
#region Variables
private int messageCount = 0;
private IPAddress multicastAddress;
private Socket multicastSocket;
#endregion Variables
#region Constructors
public MulticastClient(string MulticastGroup, int MulticastPort)
{
new MulticastClient(MulticastGroup, MulticastPort, true);
}
public MulticastClient(string MulticastGroup, int MulticastPort, bool
StartImmediately)
{
_multicastAddress = MulticastGroup;
_multicastPort = MulticastPort;
// Do we want to start?
if (StartImmediately) { StartListening(); }
}
#endregion Constructors
#region Properties
public string HostAddress
{
get
{
return _multicastAddress;
}
set
{
// TODO: Only allow the setting of the property if the client is not active
if (value != _multicastAddress)
{
_multicastAddress = value;
}
}
}
public int Port
{
get
{
return _multicastPort;
}
set
{
// TODO: Only allow the setting of the property if the client is not active
_multicastPort = value;
}
}
#endregion
#region Methods
private void ConfigureMulticastSocket()
{
// Assign the local address automatically
EndPoint localEndPoint;
MulticastOption multicastOption;
IPAddress localIPAddress = IPAddress.Any; // TODO: Possibly need to change
this to be specific
// Configure the multicast address object
multicastAddress = IPAddress.Parse(_multicastAddress);
// Create the socket object
// TODO: Make sure the socket is not already active
multicastSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram, ProtocolType.Udp);
// Now create an end point for this end. Local IP address with the multicast
port
localEndPoint = (EndPoint)new IPEndPoint(localIPAddress, _multicastPort);
// Bind the socket object to the end point
multicastSocket.Bind(localEndPoint);
// Now set the multicast options
multicastOption = new MulticastOption(multicastAddress, localIPAddress);
multicastSocket.SetSocketOption(SocketOptionLevel.IP,
SocketOptionName.AddMembership,
multicastOption);
}
private void StartListening()
{
bool complete = false; // Flag to indicate completion of processing loop
IPEndPoint groupEndPoint; // The end point to the group
EndPoint remoteEndPoint; // The other end of the socket
byte[] recievedBytes = new byte[10000]; // Bytes to receive
int recievedByteCount = 0; // Number of bytes recieved
// Configure the socket and start listening
ConfigureMulticastSocket();
// Configure the end point for the group
groupEndPoint = new IPEndPoint(multicastAddress, _multicastPort);
// Configure the other end point or where we want to retrieve data from.
// For this example we are going to accept data from anywhere, but
// we should be able to specify where we want to receive data from.
// Port 0 is given to allow the framework/OS to decide what is used.
remoteEndPoint = (EndPoint) new IPEndPoint(IPAddress.Any, 0);
// Wait for data
// TODO: This should be asynchronous
try
{
while(!complete)
{
Console.WriteLine("Waiting for multicast messages ...");
// Wait for some data
recievedByteCount = multicastSocket.ReceiveFrom(recievedBytes, ref
remoteEndPoint);
// Show we have got something
Console.WriteLine("Received {2}: {0} from {1}",
Encoding.ASCII.GetString(recievedBytes, 0, recievedByteCount),
remoteEndPoint.ToString(),
++messageCount);
}
}
catch(Exception e)
{
Console.WriteLine(e.ToString());
}
}
#endregion Methods
}
As you can see the c# code is no where near complete compared to the C code. It
has less processing, but still manages to miss the messages. The only thing I
can think of is to remove the Console.Writelines and log the messages to a log
file. Just incase this is actually causing the issue (overhead of writing out
to the console is more than writing to a file perhaps).
Marcus.
Quoting Jason Starin | Giant Head <jasonstarin at giant-head.com>:
>
>
>
>
> Hi Marcus,
>
> First off, without code, I feel like I'm going into this question blind,
> but I do have a similar example that I did find a solution for.
>
> I had a web service that was capturing web requests from several different
> forms, it then incremented a database, and then sent confirmation mails as
> well as lead emails to different targets, based upon the web data. I had
> all exceptions mailed to me, and it allowed me a little time to figure out
> about how to configure my application to work well with xsp.
>
> Here's the general idea:
>
> 1. I made receipt of requests a top priority process, running on a separate
> service, so that I always received requests. I had those requests write to
> a common xml file that was hosted in memory. Whenever my requests exceeded
> 1000 or so a minute, the service would crash if I was trying to write a file
> to disk, so instead, I had a single write at the end of each minute as part
> of a separate thread.
>
> 2. Database updates seem to be slow using the ByteFX and the MySql.Data
> ADO.net connections. I built a timer that updated with the common XML file
> every 4 minutes. That reduced the total number of database requests to a
> manageable number that gave them plenty of time to finish (all of my
> requests seem to take between 9 and 15 seconds to run almost regardless of
> their size).
>
> 3. Because mail services (I'm using sendmail on RedHat Fedora Core 2, but I
> also tested SMTP on a Win2k3 with Mono box) seemed to flake out on repeated
> connections, I batched emails, and sent them in groups, every ten minutes.
> If I allowed each process to send an email message, immediately, my dual
> processor server seemed to choke on all of the connections, and eventually
> XSP would crash and take apache with it. On Windows, I'd have a great big
> collection of emails bogged down in my logs, needing to be resent.
>
> Frankly, I don't think these are bugs, but more along the lines of
> enviornmental constraints, that you can adapt to if you map out the process
> and look for where things are flaking out. Perhaps establish a separate log
> file to watch each step through your process, and save at the end of your
> test?
>
> Send code if you get a chance, I'm interested to see where I can help, and
> have you thought about testing your C# app on a windows machine?
>
> Interesting problem,
> Jason
>
>
>
>
> From: mono-devel-list-admin at lists.ximian.com
> [mailto:mono-devel-list-admin at lists.ximian.com] On Behalf Of
> marcusmonaghan at f2s.com
> Sent: Monday, April 04, 2005 10:37 AM
> To: Mono Help
> Subject: [Mono-devel-list] UDP 40%+ loss
>
> All,
>
> I am trying to re-creating a C program in C# mono (as there are more C#
> developers in our company now) and it seems it's not behaving in the
> expected
> way.
>
> The program is very simple. It listens on a multicast group, receives data
> and
> writes it to a file. The problem is that I'm seeing roughly 40%+ missed
> messages when compared to the C program. I ran the C# and C program on the
> same
> box. On another box I send out 100 messages in 10 second bursts. The C
> program
> receives all of them whereas the C# program only receive 60 on the first
> burst
> 50 on the second 55 on the third and so on.
>
> I then (just for a laugh) unthrottled the sending program. It sent 51,000
> messages, all of which where received by the C program. The c# program
> recorded
> 7152.
>
> Anyone got any ideas? Possibly a bug?
>
> Regards,
> Marcus
> _______________________________________________
> Mono-devel-list mailing list
> Mono-devel-list at lists.ximian.com
> http://lists.ximian.com/mailman/listinfo/mono-devel-list
>
>
> _______________________________________________
> Mono-devel-list mailing list
> Mono-devel-list at lists.ximian.com
> http://lists.ximian.com/mailman/listinfo/mono-devel-list
>
Regards,
Marcus
More information about the Mono-devel-list
mailing list