The program currently works: you type in IP address, click connect, type in message, click send and the server receives and displays the message.

Client Code:

 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
}
}

I'm trying to modify it so if the server/receiver is temporarily offline when the client/sender sends a message to it, the sender will automatically wait ten seconds, then try to reconnect and resend the message.

Right now I can do that by manually waiting, then re-clicking "connect" and then "send" but I'd like the sender to handle that on its own.

Code for the form:

  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();                                 
    }
}

First time posting here, I hope I did this right. Any advice is welcome.

有帮助吗?

解决方案 2

Firstly, extract the sending of message code in a new method returning 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;
}

Then in your button click event you check if it succeeded and if not, wait and try again:

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);
    }
}

其他提示

The basic answer is to put message and destination in a queue. and attempt to send, if it succeeds remove it from the queue.

Given you have potentially multiple destinations you need a queue for each one. Dictionary<IP,List<Message>> as a raw option.

Lots of potential optimisations at that point, and extensions such as send to a group.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top