c#, попытка отправить сообщение, если офлайн автоматически переходит в спящий режим, переподключение, повторная отправка

В настоящее время программа работает: вы вводите IP-адрес, нажимаете «Подключиться», вводите сообщение, нажимаете «Отправить», и сервер получает и отображает сообщение.

Код клиента:

 public class Client
 {
    private const int DataSize = 65635;
    private byte[] data = new byte[DataSize];
    public Socket _socket;                      //the main socket
    public string strMsg;                       //sender's message string


    {
        get                                   
        {
            IPHostEntry ipHostInfo = Dns.GetHostEntry("localhost");   
            IPAddress ipAddress = ipHostInfo.AddressList[1];        
            return ipAddress.ToString();                 
        }
    }

    public EndPoint _epHost;   

    public bool Connect(string address)  
    {
        bool result = false; 
        if (string.IsNullOrEmpty(address)) return false;
        try
        {
            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
                 ProtocolType.Tcp);
            IPAddress ipAddress = IPAddress.Parse(address);  
            IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 8040);
            _epHost = (EndPoint)ipEndPoint;
            _socket.Connect(_epHost);
            result = true; 
        }
        catch (SocketException ex)
        {
            throw new Exception(ex.Message);
        }
        return result; 
    }

    // CITATION: Send() is a modified form of code by Jan Slama on his website
    // Link: http://www.csharp-examples.net/socket-send-receive/
    // License: "simple, straightforward examples suitable for copy and paste"

    public void Send(Data mailToBeSent, int offset, int timeout)
    {
        int startTickCount = Environment.TickCount;
        int sent = 0;  // how many bytes is already sent  

        data = mailToBeSent.ToByte();

            do
            {
                if (Environment.TickCount > startTickCount + timeout)
                {
                    data = null;
                    throw new Exception("Timeout.");
                }
                try
                {
                    sent += _socket.Send(data, offset + sent, 
                       data.Length - sent, SocketFlags.None);
                }
                catch (SocketException ex)
                {
                    if (ex.SocketErrorCode == SocketError.WouldBlock ||
                        ex.SocketErrorCode == SocketError.IOPending ||
                        ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
                        // socket buffer is probably full, wait and try again
                        Thread.Sleep(30);
                    else
                        throw ex;  // any serious error occurs
                }
            }
            while (sent < data.Length);
    }

    public void Close()
    {
        if (_socket != null)
        {                
            _socket.Shutdown(SocketShutdown.Both);
            _socket.Close();
        }
    }
}

public enum Command         //Commands for sender/receiver
{
    Message,                //Send a text message to the receiver
    Close,                  //Close
    Null,                   //No command
}
}

Я пытаюсь изменить его, чтобы, если сервер/получатель временно отключился, когда клиент/отправитель отправляет ему сообщение, отправитель автоматически подождет десять секунд, затем попытается повторно подключиться и повторно отправить сообщение.

Прямо сейчас я могу сделать это, подождав вручную, затем повторно щелкнув «подключиться», а затем «отправить», но я бы хотел, чтобы отправитель справился с этим самостоятельно.

Код формы:

  public partial class Form1 : Form
{

    private Client _client;

    public Form1()          
    {
        InitializeComponent();                              
        _client = new Client();                                    
        Text = string.Format("Address: {0}", _client.IpAddress);    
        btnDisconnect.Enabled = false;                              
        tbMsg.Enabled = false;                                     
        btnSend.Enabled = false;                                   
    }

    private void btnConnect_Click(object sender, EventArgs e)   
    {
        if (_client.Connect(tbAddress.Text))    
        { 
            btnDisconnect.Enabled = true;       
            tbMsg.Enabled = true;               
            btnSend.Enabled = true;             
            tsLabel.Text = "Online";            
        }
    } 


    private void btnSend_Click(object sender, EventArgs e) 
    {
       try
       {
          Data mailToBeSent = new Data();            
          mailToBeSent.cmdCommand = Command.Message;
          mailToBeSent.ipAddress = _client.IpAddress; 
          mailToBeSent.strMessage = tbMsg.Text;      
          _client.Send(mailToBeSent, 0, 1000);       
          tbMsg.Text = string.Empty;                         
        }
        catch (Exception)
        {
          MessageBox.Show("Unable to deliver mail to receiver.", "Client", 
            MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }


    private void btnDisconnect_Click(object sender, EventArgs e) 
    {
        Data mailToBeSent = new Data();                    
        mailToBeSent.cmdCommand = Command.Close;           
        mailToBeSent.ipAddress = _client.IpAddress;        
        mailToBeSent.strMessage = string.Empty;            
        _client.Send(mailToBeSent, 0, 1000);               
        _client.Close();                                 
    }
}

Пишу сюда первый раз, надеюсь правильно сделал. Любые советы приветствуются.


person user3260298    schedule 02.02.2014    source источник
comment
Разрешено ли пользователю снова нажать кнопку и отправить другое сообщение, пока вы все еще пытаетесь отправить предыдущее сообщение? Если да, то какое сообщение должно иметь приоритет?   -  person noseratio    schedule 02.02.2014


Ответы (2)


Во-первых, извлеките отправку кода сообщения в новый метод, возвращающий bool:

private bool SendMessage()
{
   try
   {
      Data mailToBeSent = new Data();            
      mailToBeSent.cmdCommand = Command.Message;
      mailToBeSent.ipAddress = _client.IpAddress; 
      mailToBeSent.strMessage = tbMsg.Text;      
      _client.Send(mailToBeSent, 0, 1000);       
      tbMsg.Text = string.Empty;                         
    }
    catch (Exception)
    {
       return false;
    }

    return true;
}

Затем в событии нажатия кнопки вы проверяете, удалось ли это, а если нет, подождите и повторите попытку:

private void btnSend_Click(object sender, EventArgs e) 
{
    int noOfRetries = 0;

    while(!SendMessage() && noOfRetries < 3) // Or whatever no of retries you want
    {
        noOfRetries++;
        Thread.Sleep(10000);
    }
}
person Håkan Fahlstedt    schedule 02.02.2014
comment
Это заблокирует пользовательский интерфейс на срок до 30 секунд, в худшем случае. - person noseratio; 02.02.2014
comment
Я ценю информацию; не понимал, что пытаюсь сделать слишком много одним методом. И хотя в других программах 30 секунд блокировки могут быть проблемой, в данном случае все должно работать нормально. - person user3260298; 02.02.2014
comment
Хорошо, если вы найдете какой-либо из приведенных ответов удовлетворительным, вы должны отметить его как ответ на свой вопрос серой галочкой. Это поможет другим увидеть, что на вопрос получен ответ. - person Håkan Fahlstedt; 02.02.2014

Основной ответ - поместить сообщение и пункт назначения в очередь. и попытаться отправить, в случае успеха удалить его из очереди.

Учитывая, что у вас есть потенциально несколько пунктов назначения, вам нужна очередь для каждого из них. Dictionary<IP,List<Message>> как необработанный вариант.

На тот момент было много потенциальных оптимизаций и расширений, таких как отправка в группу.

person Tony Hopkinson    schedule 02.02.2014