Ejemplo n.º 1
0
        private void AsyncReceive(IAsyncResult ar)
        {
            bool readAsync = false;
            do {
                if (receiveState == INIT_RECEIVE) {
                    buffer = new byte[48];
                    receivedLength = 0;
                    receiveState = HEADER_RECEIVE;
                    receivedMessage = new SpreadMessage();
                } else {
                    if (receivedLength != buffer.Length) {
                        int size = stream.EndRead(ar);
                        if (size == 0)
                            throw new SpreadException("Connection closed while reading");
                        receivedLength += size;
                    }
                    if (receivedLength == buffer.Length)
                        switch (receiveState) {
                            case HEADER_RECEIVE:
                                byte[] header = buffer;

                                int headerIndex = 0;
                                // Get service type.
                                ////////////////////
                                receivedMessage.ServiceType = toInt(header, headerIndex);
                                headerIndex += 4;

                                // Get the sender.
                                //////////////////
                                ///
                                receivedMessage.Sender = toGroup(header, headerIndex);
                                headerIndex += MAX_GROUP_NAME;

                                // Get the number of groups.
                                ////////////////////////////
                                numGroups = toInt(header, headerIndex);
                                headerIndex += 4;

                                // Get the hint/type.
                                /////////////////////
                                int hint = toInt(header, headerIndex);
                                headerIndex += 4;

                                // Get the data length.
                                ///////////////////////
                                int dataLen = toInt(header, headerIndex);
                                headerIndex += 4;

                                // Does the header need to be flipped?
                                // (Checking for a daemon server endian-mismatch)
                                /////////////////////////////////////////////////

                                if(sameEndian(receivedMessage.ServiceType) == false) {
                                    // Flip them.
                                    /////////////
                                    receivedMessage.ServiceType = flip(receivedMessage.ServiceType);
                                    numGroups = flip(numGroups);
                                    dataLen = flip(dataLen);

                                    // The daemon endian-mismatch.
                                    //////////////////////////////
                                    daemonEndianMismatch = true;
                                }
                                else {
                                    // The daemon endian-mismatch.
                                    //////////////////////////////
                                    daemonEndianMismatch = false;
                                }

                                receivedMessage.Data = new byte[dataLen];

                                // Is this a regular message?
                                /////////////////////////////
                                if( receivedMessage.IsRegular || receivedMessage.IsReject ) {
                                    // Does the hint need to be flipped?
                                    // (Checking for a sender endian-mismatch)
                                    //////////////////////////////////////////
                                    if(sameEndian(hint) == false) {
                                        hint = flip(hint);
                                        receivedMessage.EndianMismatch = true;
                                    }
                                    else {
                                        receivedMessage.EndianMismatch = false;
                                    }

                                    // Get the type from the hint.
                                    //////////////////////////////
                                    hint = clearEndian(hint);
                                    hint >>= 8;
                                    hint &= 0x0000FFFF;
                                    receivedMessage.Type = (short)hint;
                                }
                                else {
                                    // This is not a regular message.
                                    /////////////////////////////////
                                    receivedMessage.Type = -1;
                                    receivedMessage.EndianMismatch = false;
                                }
                                if( receivedMessage.IsReject ) {
                                    buffer = new byte[4];
                                    receivedLength = 0;
                                    receiveState = OLD_TYPE_RECEIVE;
                                } else {
                                    buffer = new byte[numGroups * MAX_GROUP_NAME];
                                    receivedLength = 0;
                                    receiveState = GROUPS_RECEIVE;
                                }
                                break;
                            case OLD_TYPE_RECEIVE:
                                int oldType = toInt(buffer, 0);
                                if ( sameEndian(receivedMessage.ServiceType) == false )
                                    oldType = flip(oldType);
                                receivedMessage.ServiceType = (SpreadMessage.REJECT_MESS | oldType);
                                buffer = new byte[numGroups * MAX_GROUP_NAME];
                                receivedLength = 0;
                                receiveState = GROUPS_RECEIVE;
                                break;
                            case GROUPS_RECEIVE:
                                // Clear the endian type.
                                /////////////////////////
                                receivedMessage.ServiceType = clearEndian(receivedMessage.ServiceType);

                                // Get the groups from the buffer.
                                //////////////////////////////////
                                for(int bufferIndex = 0 ; bufferIndex < buffer.Length ; bufferIndex += MAX_GROUP_NAME) {
                                    // Translate the name into a group and add it to the vector.
                                    ////////////////////////////////////////////////////////////
                                    receivedMessage.AddGroup(toGroup(buffer, bufferIndex));
                                }
                                buffer = receivedMessage.Data;
                                receivedLength = 0;
                                receiveState = DATA_RECEIVE;
                                break;
                            case DATA_RECEIVE:
                                // Is it a membership message?
                                //////////////////////////////
                                if(receivedMessage.IsMembership) {
                                    // Create a membership info object.
                                    ///////////////////////////////////
                                    receivedMessage.membershipInfo = new MembershipInfo(this, receivedMessage, daemonEndianMismatch);

                                    // Is it a regular membership message?
                                    //////////////////////////////////////
                                    if(receivedMessage.membershipInfo.IsRegularMembership) {
                                        // Find which of these groups is the local connection.
                                        //////////////////////////////////////////////////////
                                        receivedMessage.Type = (short)receivedMessage.groups.IndexOf(PrivateGroup);
                                    }
                                }
                                else {
                                    // There's no membership info.
                                    //////////////////////////////
                                    receivedMessage.membershipInfo = null;
                                }
                                if (OnRegularMessage !=null  && receivedMessage.IsRegular)
                                    OnRegularMessage(receivedMessage);
                                else if (OnMembershipMessage != null && receivedMessage.IsMembership)
                                    OnMembershipMessage(receivedMessage);
                                else {
                                    lock (rsynchro) {
                                        messageWaiting = true;
                                        Monitor.Pulse(rsynchro);
                                        Monitor.Wait(rsynchro);
                                    }
                                }
                                buffer = new byte[48];
                                receivedLength = 0;
                                receiveState = HEADER_RECEIVE;
                                receivedMessage = new SpreadMessage();
                                break;
                        }
                }
                try {
                    // read sync if data available
                    while(stream.DataAvailable && receivedLength < buffer.Length) {
                        int size = stream.Read(buffer,receivedLength,buffer.Length-receivedLength);
                        if (size == 0)
                            throw new SpreadException("Connection closed while reading");
                        receivedLength += size;
                    }
                    if (receivedLength != buffer.Length) {
                        // no more data - continue async read
                        stream.BeginRead(buffer,receivedLength,buffer.Length-receivedLength,new AsyncCallback(AsyncReceive),null);
                        readAsync = true;
                    }
                } catch (Exception e) {
                    throw new SpreadException("BeginRead(): " + e);
                }
            } while (!readAsync);
        }
Ejemplo n.º 2
0
        // Sends the message.
        /////////////////////
        /**
             * mcasts a message.  The message will be sent to all the groups specified in
             * the message.
             *
             * @param  message  the message to mcast
             * @throws  SpreadException  if there is no connection or if there is any error sending the message
             */
        public void Multicast(SpreadMessage message)
        {
            // Check if we're connected.
            ////////////////////////////
            if(connected == false) {
                throw new SpreadException("Not connected.");
            }

            // The groups this message is going to.
            ///////////////////////////////////////
            SpreadGroup[] groups = message.Groups;

            // The message data.
            ////////////////////
            byte[] data = message.Data;

            // Calculate the total number of bytes.
            ///////////////////////////////////////
            int numBytes = 16;  // serviceType, numGroups, type/hint, dataLen
            numBytes += MAX_GROUP_NAME;  // private group
            numBytes += (MAX_GROUP_NAME * groups.Length);  // groups

            if (numBytes + data.Length > MAX_MESSAGE_LENGTH ) {
                throw new SpreadException("Message is too long for a Spread Message");
            }
            // Allocate the send buffer.
            ////////////////////////////
            byte[] buffer = new byte[numBytes];
            int bufferIndex = 0;

            // The service type.
            ////////////////////
            toBytes(message.ServiceType, buffer, bufferIndex);
            bufferIndex += 4;

            // The private group.
            /////////////////////
            toBytes(group, buffer, bufferIndex);
            bufferIndex += MAX_GROUP_NAME;

            // The number of groups.
            ////////////////////////
            toBytes(groups.Length, buffer, bufferIndex);
            bufferIndex += 4;

            // The service type and hint.
            /////////////////////////////
            toBytes(((int)message.Type << 8) & 0x00FFFF00, buffer, bufferIndex);
            bufferIndex += 4;

            // The data length.
            ///////////////////
            toBytes(data.Length, buffer, bufferIndex);
            bufferIndex += 4;

            // The group names.
            ///////////////////
            for(int i = 0 ; i < groups.Length ; i++) {
                toBytes(groups[i], buffer, bufferIndex);
                bufferIndex += MAX_GROUP_NAME;
            }

            try {
                stream.Write(buffer,0,buffer.Length);
                stream.Write(data,0,data.Length);
            }
            catch(Exception e) {
                throw new SpreadException("Write(): " + e.ToString());
            }
        }
Ejemplo n.º 3
0
 // Receives numMessages new messages.
 /////////////////////////////////////
 /**
  * Receives <code>numMessages</code> messages on the connection and returns them in an array.
  * If there are not <code>numMessages</code> messages waiting, the call will block until there are
  * enough messages available.
  *
  * @param  numMessages  the number of messages to receive
  * @return an array of messages
  * @throws  SpreadException  if there is no connection or if there is any error reading the messages
  */
 public SpreadMessage[] Receive(int numMessages)
 {
     // Allocate the messages array.
     ///////////////////////////////
     SpreadMessage[] messages = new SpreadMessage[numMessages];
     for(int i = 0 ; i < numMessages ; i++) {
         messages[i] = Receive();
     }
     // Return the array.
     ////////////////////
     return messages;
 }
Ejemplo n.º 4
0
        // Disconnects from the spread daemon.
        //////////////////////////////////////
        /**
         * Disconnects the connection to the daemon.  Nothing else should be done with this connection
         * after disconnecting it.
         *
         * @throws  SpreadException  if there is no connection or there is an error disconnecting
         * @see  SpreadConnection#connect(InetAddress, int, String, boolean, boolean)
         */
        public void Disconnect()
        {
            // Check if we're connected.
            ////////////////////////////
            if(connected == false) {
                throw new SpreadException("Not connected.");
            }

            // Get a new message.
            /////////////////////
            SpreadMessage killMessage = new SpreadMessage();

            // Send it to our private group.
            ////////////////////////////////
            killMessage.AddGroup(group);

            // Set the service type.
            ////////////////////////
            killMessage.ServiceType = SpreadMessage.KILL_MESS;

            // Send the message.
            ////////////////////
            Multicast(killMessage);

            // Close the socket.
            ////////////////////
            try {
                socket.Close();
            }
            catch(Exception e) {
                throw new SpreadException("close(): " + e);
            }
        }
Ejemplo n.º 5
0
 // Sends the array of messages.
 ///////////////////////////////
 /**
  * mcasts an array of messages.  Each message will be sent to all the groups specified in
  * the message.
  *
  * @param  messages  the messages to mcast
  * @throws  SpreadException  if there is no connection or if there is any error sending the messages
  */
 public void Multicast(SpreadMessage[] messages)
 {
     // Go through the array.
     ////////////////////////
     for(int i = 0 ; i < messages.Length ; i++) {
         // Send this message.
         /////////////////////
         Multicast(messages[i]);
     }
 }
Ejemplo n.º 6
0
        public void Leave()
        {
            // Check if we can leave.
            /////////////////////////
            if(connection == null) {
                throw new SpreadException("No group to leave.");
            }

            // Get a new message.
            /////////////////////
            SpreadMessage leaveMessage = new SpreadMessage();

            // Set the group we're sending to.
            //////////////////////////////////
            leaveMessage.AddGroup(name);

            // Set the service type.
            ////////////////////////
            leaveMessage.ServiceType = SpreadMessage.LEAVE_MESS;

            // Send the message.
            ////////////////////
            connection.Multicast(leaveMessage);

            // No longer connected.
            ///////////////////////
            connection = null;
        }
Ejemplo n.º 7
0
        // Constructor.
        ///////////////
        internal MembershipInfo(SpreadConnection connection,SpreadMessage message, bool daemonEndianMismatch)
        {
            // Set local variables.
            ///////////////////////
            this.serviceType = message.ServiceType;
            this.group = message.Sender;
            this.members = message.Groups;

            // Is this a regular membership message.
            ////////////////////////////////////////
            if(IsRegularMembership) {
                // Extract the groupID.
                ///////////////////////
                int dataIndex = 0;
                int[] id = new int[3];
                    id[0] = SpreadConnection.toInt(message.Data, dataIndex);
                dataIndex += 4;
                id[1] = SpreadConnection.toInt(message.Data, dataIndex);
                dataIndex += 4;
                id[2] = SpreadConnection.toInt(message.Data, dataIndex);
                dataIndex += 4;
                // Endian-flip?
                ///////////////
                if(daemonEndianMismatch) {
                    id[0] = SpreadConnection.flip(id[0]);
                    id[1] = SpreadConnection.flip(id[1]);
                    id[2] = SpreadConnection.flip(id[2]);
                }

                // Create the group ID.
                ///////////////////////
                this.groupID = new GroupID(id[0], id[1], id[2]);

                // Get the number of groups.
                ////////////////////////////
                int numGroups = SpreadConnection.toInt(message.Data, dataIndex);
                if(daemonEndianMismatch) {
                    numGroups = SpreadConnection.flip(numGroups);
                }
                dataIndex += 4;

                // Get the groups.
                //////////////////
                this.groups = new SpreadGroup[numGroups];
                for(int i = 0 ; i < numGroups ; i++) {
                    this.groups[i] = connection.toGroup(message.Data, dataIndex);
                    dataIndex += SpreadConnection.MAX_GROUP_NAME;
                }
            }
        }
Ejemplo n.º 8
0
        public void Join(SpreadConnection c, string groupName)
        {
            // Check if this group has already been joined.
            ///////////////////////////////////////////////
            if(this.connection != null) {
                throw new SpreadException("Already joined.");
            }

            // Set member variables.
            ////////////////////////
            this.connection = c;
            this.name = groupName;

            // Error check the name.
            ////////////////////////
            byte[] bytes;
                try {
                    bytes = System.Text.Encoding.ASCII.GetBytes(name);
                }
                catch(Exception e) {
                    throw new SpreadException("Encoding not supported: "+e);
                }
            for(int i = 0 ; i < bytes.Length ; i++) {
                // Make sure the byte (character) is within the valid range.
                ////////////////////////////////////////////////////////////
                if((bytes[i] < 36) || (bytes[i] > 126)) {
                    throw new SpreadException("Illegal character in group name.");
                }
            }

            // Get a new message.
            /////////////////////
            SpreadMessage joinMessage = new SpreadMessage();

            // Set the group we're sending to.
            //////////////////////////////////
            joinMessage.AddGroup(name);

            // Set the service type.
            ////////////////////////
            joinMessage.ServiceType = SpreadMessage.JOIN_MESS;

            // Send the message.
            ////////////////////
            connection.Multicast(joinMessage);
        }
Ejemplo n.º 9
0
    private void DisplayMessage(SpreadMessage msg)
    {
        try {
            Console.WriteLine("*****************RECTHREAD Received Message************");
            if(msg.IsRegular) {
                Console.Write("Received a ");
                if(msg.IsUnreliable)
                    Console.Write("UNRELIABLE");
                else if(msg.IsReliable)
                    Console.Write("RELIABLE");
                else if(msg.IsFifo)
                    Console.Write("FIFO");
                else if(msg.IsCausal)
                    Console.Write("CAUSAL");
                else if(msg.IsAgreed)
                    Console.Write("AGREED");
                else if(msg.IsSafe)
                    Console.Write("SAFE");
                Console.WriteLine(" message.");

                Console.WriteLine("Sent by  " + msg.Sender + ".");

                Console.WriteLine("Type is " + msg.Type + ".");

                if(msg.EndianMismatch == true)
                    Console.WriteLine("There is an endian mismatch.");
                else
                    Console.WriteLine("There is no endian mismatch.");

                SpreadGroup[] groups = msg.Groups;
                Console.WriteLine("To " + groups.Length + " groups.");

                byte[] data = msg.Data;
                Console.WriteLine("The data is " + data.Length + " bytes.");

                Console.WriteLine("The message is: " + System.Text.Encoding.ASCII.GetString(data));
            }
            else if ( msg.IsMembership ) {
                MembershipInfo info = msg.MembershipInfo;

                if(info.IsRegularMembership) {
                    //SpreadGroup[] groups = msg.Groups;
                    SpreadGroup[] groups = info.Members;

                    Console.WriteLine("Received a REGULAR membership.");
                    Console.WriteLine("For group " + info.Group + ".");
                    Console.WriteLine("With " + groups.Length + " members.");
                    Console.WriteLine("Members: "); // + msg.Type + ".");
                    for(int i = 0 ; i < groups.Length ; i++)
                        Console.WriteLine("  " + groups[i]);

                    Console.WriteLine("Group ID is " + info.GroupID);

                    Console.Write("Due to ");
                    if(info.IsCausedByJoin) {
                        Console.WriteLine("the JOIN of " + info.Joined + ".");
                    }
                    else if(info.IsCausedByLeave) {
                        Console.WriteLine("the LEAVE of " + info.Left + ".");
                    }
                    else if(info.IsCausedByDisconnect) {
                        Console.WriteLine("the DISCONNECT of " + info.Disconnected + ".");
                    }
                    else if(info.IsCausedByNetwork) {
                        SpreadGroup[] stayed = info.Stayed;
                        Console.WriteLine("NETWORK change.");
                        Console.WriteLine("VS set has " + stayed.Length + " members:");
                        for(int i = 0 ; i < stayed.Length ; i++)
                            Console.WriteLine("  " + stayed[i]);
                    }
                }
                else if(info.IsTransition) {
                    Console.WriteLine("Received a TRANSITIONAL membership for group " + info.Group);
                }
                else if(info.IsSelfLeave) {
                    Console.WriteLine("Received a SELF-LEAVE message for group " + info.Group);
                }
            } else if ( msg.IsReject ) {
                // Received a Reject message
                Console.Write("Received a ");
                if(msg.IsUnreliable)
                    Console.Write("UNRELIABLE");
                else if(msg.IsReliable)
                    Console.Write("RELIABLE");
                else if(msg.IsFifo)
                    Console.Write("FIFO");
                else if(msg.IsCausal)
                    Console.Write("CAUSAL");
                else if(msg.IsAgreed)
                    Console.Write("AGREED");
                else if(msg.IsSafe)
                    Console.Write("SAFE");
                Console.WriteLine(" REJECTED message.");

                Console.WriteLine("Sent by  " + msg.Sender + ".");

                Console.WriteLine("Type is " + msg.Type + ".");

                if(msg.EndianMismatch == true)
                    Console.WriteLine("There is an endian mismatch.");
                else
                    Console.WriteLine("There is no endian mismatch.");

                SpreadGroup[] groups = msg.Groups;
                Console.WriteLine("To " + groups.Length + " groups.");

                byte[] data = msg.Data;
                Console.WriteLine("The data is " + data.Length + " bytes.");

                Console.WriteLine("The message is: " + System.Text.Encoding.ASCII.GetString(data));
            } else {
                Console.WriteLine("Message is of unknown type: " + msg.ServiceType );
            }
        }
        catch(Exception e) {
            Console.WriteLine(e);
            Environment.Exit(1);
        }
    }
Ejemplo n.º 10
0
	public void messageReceived(SpreadMessage message) {
		DisplayMessage(message);
	}
Ejemplo n.º 11
0
	private void UserCommand() {
		// Show the prompt.
		///////////////////
		Console.Write("\n" + 
			"User> ");
		
		// Get the input.
		/////////////////
		string[] tokens = Console.ReadLine().Split(new Char[] {' '});
		
		// Check what it is.
		////////////////////
		SpreadMessage msg;
		char command = tokens[0].Length>0?tokens[0][0]:'\n';
		try {
			switch(command) {
					//JOIN
				case 'j':
					// Join the group.
					//////////////////
					if(tokens.Length > 1) {
						group = new SpreadGroup();
						group.Join(connection, tokens[1]);
						Console.WriteLine("Joined " + group + ".");
					}
					else {
						System.Console.Error.WriteLine("No group name.");
					}
				
					break;
				
					//LEAVE
				case 'l':
					// Leave the group.
					///////////////////
					if(group != null) {
						group.Leave();
						Console.WriteLine("Left " + group + ".");
					}
					else {
						Console.WriteLine("No group to leave.");
					}
				
					break;
				
					//SEND
				case 's':
					// Get a new outgoing message.
					//////////////////////////////
					msg = new SpreadMessage();
					msg.IsSafe = true;
				
					// Add the groups.
					//////////////////
					for(int i=1;i < tokens.Length;i++)
						msg.AddGroup(tokens[i]);
				
					// Get the message.
					///////////////////
					Console.Write("Enter message: ");
					msg.Data = System.Text.Encoding.ASCII.GetBytes(Console.ReadLine());
				
					// Send it.
					///////////
					connection.Multicast(msg);
				
					// Increment the sent message count.
					////////////////////////////////////
					numSent++;
				
					// Show how many were sent.
					///////////////////////////
					Console.WriteLine("Sent message " + numSent + ".");
				
					break;
				
					//BURST
				case 'b':				
					// Get a new outgoing message.
					//////////////////////////////
					msg = new SpreadMessage();
					msg.IsSafe = true;;
				
					// Get the group.
					/////////////////
					if(tokens.Length > 1) {
						msg.AddGroup(tokens[1]);
					}
					else {
						Console.Error.WriteLine("No group name.");
						break;
					}
				
					// Get the message size.
					////////////////////////
					Console.Write("Enter the size of each message: ");
					int size = int.Parse(Console.ReadLine());
					if(size < 0)
						size = 20;
				
					// Send the messages.
					/////////////////////
					Console.WriteLine("Sending 10 messages of " + size + " bytes.");
					byte[] data = new byte[size];
					for(int i = 0 ; i < size ; i++) {
						data[i] = 0;
					}
					for(int i = 0 ; i < 10 ; i++) {
						// Increment the sent message count.
						////////////////////////////////////
						numSent++;
					
						// Set the message data.
						////////////////////////
						byte[] mess = System.Text.Encoding.ASCII.GetBytes("mess num " + i);
						Array.Copy(mess, 0, data, 0, mess.Length);
						msg.Data = data;
					
						// Send the message.
						////////////////////
						connection.Multicast(msg);
						Console.WriteLine("Sent message " + (i + 1) + " (total " + numSent + ").");
					}
				
					break;
				
					//RECEIVE
				case 'r':
					if(listening == false) {
						// Receive a message.
						/////////////////////
						DisplayMessage(connection.Receive());
					}
				
					break;
				
					//POLL
				case 'p':
					if(listening == false) {
						// Poll.
						////////
						if(connection.Poll() == true) {
							Console.WriteLine("There is a message waiting.");
						}
						else {
							Console.WriteLine("There is no message waiting.");
						}
					}
				
					break;
				
					//THREAD
				case 't':
					if(listening) {
						connection.OnRegularMessage -= handler;
						connection.OnMembershipMessage -= handler;
						if (rt.threadSuspended)
							lock(rt) {
								Monitor.Pulse(rt);
								rt.threadSuspended = false;
							}
					}
					else {
						connection.OnRegularMessage += handler;
						connection.OnMembershipMessage += handler;
						lock(rt) {
							rt.threadSuspended = true;
						}
					}
				
					listening = !listening;

					break;

					//QUIT
				case 'q':
					// Disconnect.
					//////////////
					connection.Disconnect();
				
					// Quit.
					////////
					Environment.Exit(0);
				
					break;
				
				default:
					// Unknown command.
					///////////////////
					Console.WriteLine("Unknown command");
				
					// Show the menu again.
					///////////////////////
					PrintMenu();
					break;
			}
		}
		catch(Exception e) {
			Console.WriteLine(e);
			Environment.Exit(1);
		}
	}
Ejemplo n.º 12
0
	public Flooder(String user, int numMessages, int numBytes, String address, int port, bool readOnly, bool writeOnly) {
		try {
			// Start timer.
			///////////////
			DateTime startTime = DateTime.Now;
			
			// Connect.
			///////////
			SpreadConnection connection = new SpreadConnection();
			connection.Connect(address, port, user, false, false);
			string privateName = connection.PrivateGroup.ToString();
			
			// Join.
			////////
			SpreadGroup group = new SpreadGroup();
			if(readOnly) {
				Console.WriteLine("Only receiving messages");
				group.Join(connection, "flooder");
			}
			else if(writeOnly) {
				Console.WriteLine("Starting multicast of " + numMessages + " messages, " + numBytes + " bytes each (self discarding).");
			}
			else {
				group.Join(connection, "flooder");
				Console.WriteLine("Starting multicast of " + numMessages + " messages, " + numBytes + " bytes each.");
			}
			
			// The outgoing message.
			////////////////////////
			SpreadMessage mout = null;
			if(readOnly == false) {
				mout = new SpreadMessage();
				mout.IsSafe = true;
				mout.Data = new byte[numBytes];
				mout.AddGroup("flooder");
			}
			
			// Send/Receive.
			////////////////
			for(int i = 1 ; i <= numMessages ; i++) {
				// Send.
				////////
				if(readOnly == false) {
					connection.Multicast(mout);
					}
				
				// Receive.
				///////////
				if((readOnly) || ((i > 50) && (writeOnly == false))) {
					SpreadMessage min;
					do {
						min = connection.Receive();
					}
					while((readOnly == false) && (privateName.Equals(min.Sender.ToString()) == false));
				}
				
				// Report.
				//////////
				if((i % 1000) == 0) {
					Console.WriteLine("Completed " + i + " messages");
				}
			}
			
			// Stop timer.
			//////////////
			DateTime stopTime = DateTime.Now;
			TimeSpan time = stopTime.Subtract(startTime);
			double Mbps = numBytes;
			Mbps *= numMessages;
			Mbps *= 8;
			if((readOnly == false) && (writeOnly == false))
				Mbps *= 2;
			Mbps *= 1000;
			Mbps /= time.TotalMilliseconds;
			Mbps /= (1024 * 1024);
			Console.WriteLine("Time: " + time + "ms (" + (int)Mbps + "." + (((int)(Mbps * 100)) % 100) + " Mbps)");
		}
		catch(Exception e) {
			Console.WriteLine(e);
		}
	}