private void ProcessSendQueue()
        {
            Log(LogLevel.Info, "Send queue started");

            IPEndPoint remoteIPEndPoint = null;
            IPAddress  ipAddress        = IPAddress.Parse(_multicastIPAddress);

            if (ipAddress != null)
            {
                remoteIPEndPoint = new IPEndPoint(ipAddress, _multicastPort);
            }

            while (_isStarted)
            {
                CommunicationMessage message = null;
                lock (_sendQueue.SyncRoot)
                {
                    if (_isStarted && _sendQueue.Count > 0)
                    {
                        message = _sendQueue.Dequeue() as CommunicationMessage;
                    }
                }
                if (message != null)
                {
                    Log(LogLevel.Info, "Begin sending data.                Length: " + message.Data.Length.ToString().PadLeft(5));
                    char[]   dataToSend = message.Data.ToCharArray();
                    Encoding encoding   = Encoding.UTF8;
                    byte[]   buffer     = encoding.GetBytes(dataToSend, 0, dataToSend.Length);

                    if (_logLevel >= LogLevel.Full)
                    {
                        StringBuilder sb = new StringBuilder();
                        sb.Append("Data to send.                      Length: " + dataToSend.Length.ToString().PadLeft(5) + " (" + buffer.Length.ToString().PadLeft(5) + " bytes)");
                        sb.Append(Environment.NewLine);
                        sb.Append("[begin]");
                        sb.Append(Environment.NewLine);
                        sb.Append(message.Data);
                        sb.Append(Environment.NewLine);
                        sb.Append("[end]");
                        Log(LogLevel.Full, sb.ToString());
                    }
                    else
                    {
                        Log(LogLevel.Info, "Data to send.                      Length: " + dataToSend.Length.ToString().PadLeft(5) + " (" + buffer.Length.ToString().PadLeft(5) + " bytes)");
                    }

                    if (message.ToAll || message.IsMulticast)
                    {
                        if (remoteIPEndPoint != null)
                        {
                            Log(LogLevel.Info, "Sending data via multicast");
                            _multicastSocket.SendTo(buffer, remoteIPEndPoint);
                            Log(LogLevel.Info, "End sending data                   Length: " + dataToSend.Length.ToString().PadLeft(5) + " (" + buffer.Length.ToString().PadLeft(5) + " bytes) via Multicast");
                        }
                    }

                    int i = 0;
                    int nrOfRecipients = 0;         // Just displayed in the logfile
                    while (i < _socketList.Count)
                    {
                        Socket     socket     = _socketList[i];
                        IPEndPoint ipEndPoint = socket.RemoteEndPoint as IPEndPoint;
                        if (ipEndPoint != null)
                        {
                            try
                            {
                                socket.Send(buffer);
                                nrOfRecipients++;
                            }
                            catch (SocketException)
                            {
                                CloseSocket(ref socket);
                                _socketList.RemoveAt(i);
                                i--;
                                if (ClientDisconnected != null)
                                {
                                    ClientDisconnected.BeginInvoke(this, new ClientConnectionEventArgs(ipEndPoint), null, null);
                                }
                            }
                            i++;
                        }
                    }
                    Log(LogLevel.Info, "End sending data.                  Length: " + dataToSend.Length.ToString().PadLeft(5) + " (" + buffer.Length.ToString().PadLeft(5) + " bytes) to " + nrOfRecipients.ToString().PadLeft(2) + "/" + _socketList.Count + " recipients");
                }
                Thread.Sleep(10);
            }
            Log(LogLevel.Info, "Send queue stopped");
        }
        private void StartListening(object stateInfo)
        {
            string     savedData      = string.Empty;
            Socket     socket         = (Socket)stateInfo;
            IPEndPoint remoteEndPoint = (IPEndPoint)socket.RemoteEndPoint;

            Log(LogLevel.Info, "Start listening on                 " + remoteEndPoint);
            byte[] buffer = new byte[_bufferSize];
            while (_isStarted && socket != null && socket.Connected)
            {
                try
                {
                    int received = socket.Receive(buffer);
                    if (received == 0)
                    {
                        // Client disconnected
                        if (_isStarted)
                        {
                            _socketList.Remove(socket);
                            Log(LogLevel.Info, "The client closed the connection");
                        }
                        CloseSocket(ref socket);
                    }
                    else
                    {
                        IPEndPoint ipEndPoint = socket.RemoteEndPoint as IPEndPoint;
                        Encoding   encoding   = Encoding.UTF8;
                        string     data       = encoding.GetString(buffer, 0, received);
                        if (_logLevel >= LogLevel.Full)
                        {
                            StringBuilder sb = new StringBuilder();
                            sb.Append("Data received                      Length: " + data.Length.ToString().PadLeft(5) + " (" + received.ToString().PadLeft(5) + " bytes) from: " + ipEndPoint.Address);

                            sb.Append(Environment.NewLine);
                            sb.Append("[begin]");
                            sb.Append(Environment.NewLine);
                            sb.Append(data);
                            sb.Append(Environment.NewLine);
                            sb.Append("[end]");
                            Log(LogLevel.Full, sb.ToString());
                        }
                        else
                        {
                            Log(LogLevel.Info, "Data received                      Length: " + data.Length.ToString().PadLeft(5) + " (" + received.ToString().PadLeft(5) + " bytes) from: " + ipEndPoint.Address);
                        }

                        savedData += data;

                        const string messageEnd = "</Message>";
                        // do we have a complete message?
                        int indexOfEOM = savedData.IndexOf(messageEnd);
                        while (indexOfEOM != -1)
                        {
                            int messageLength = indexOfEOM + messageEnd.Length;
                            lock (_receiveQueue.SyncRoot)
                            {
                                string completeMessage = savedData.Substring(0, messageLength);
                                _receiveQueue.Enqueue(new CommunicationMessage(completeMessage, false));
                            }
                            if (savedData.Length > messageLength)               // received (the start of) another message
                            {
                                savedData  = savedData.Substring(messageLength);
                                indexOfEOM = savedData.IndexOf(messageEnd);
                            }
                            else
                            {
                                savedData = string.Empty;
                                break;
                            }
                        }
                    }
                }
                catch (SocketException socketException)
                {
                    LogException(socketException);
                }
                catch (Exception exception)
                {
                    LogException(exception);
                }
                Thread.Sleep(10);
            }
            if (ClientDisconnected != null)
            {
                ClientDisconnected.BeginInvoke(this, new ClientConnectionEventArgs(remoteEndPoint), null, null);
            }
            Log(LogLevel.Info, "Stopped listening on               " + remoteEndPoint);
        }