0

全部,我在 C# 中使用异步套接字。我的问题是:我想等待回调完成连接,因为我需要立即将信息发送到服务器。

这是一个代码片段:

class InternetConnector
{
    private struct ConnectionData
    {
        public Action<Exception> ErrorHandler { get; set; }
        public Socket Socket { get; set; }
    }
    public void ConnectToHost(Action<Exception> errorHandler)
    {
        IPEndPoint ip = new IPEndPoint(IPAddress.Parse(connector_host), connector_port);
        client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        var ConnectionData = new ConnectionData { ErrorHandler = errorHandler, Socket = client };
        client.Blocking = true;
        client.BeginConnect(ip, new AsyncCallback(ConnectCallback), ConnectionData);
        connectDone.WaitOne(100);
    }

    private static void ConnectCallback(IAsyncResult ar)
    {
        ConnectionData connectionData = new ConnectionData();
        try
        {
            connectionData = (ConnectionData)ar.AsyncState;
            connectionData.Socket.EndConnect(ar);
            connectDone.Set();
            Connected = true;
        }
        catch (Exception e)
        {
            if (connectionData.ErrorHandler != null)
                connectionData.ErrorHandler(e);
        }
    }
}

public partial class Form1 : Form
{
    private bool isRunning = false;
    private InternetConnector client = new InternetConnector();

    private void AsyncErrorHandler(Exception e)
    {
        if (status.InvokeRequired)
        {
            status.BeginInvoke(new Action(() => AsyncErrorHandler(e)));
            return;
        }
        InternetConnector.Connected = false;
        isRunning = false;
        startStop.Text = "Start";
        status.ForeColor = Color.Red;
        status.Text = "Socket Error: " + e.Message;
    }

    private void startStop_Click(object sender, EventArgs e)
    {
        if (!isRunning || !InternetConnector.Connected)
        {
            if (!InternetConnector.Connected)
            {
                client.SetAddress(ipAddress.Text);
                client.SetPort(Convert.ToInt32(connectionport.Text));
                client.ConnectToHost( AsyncErrorHandler );
                status.Text = "Signals Receiver: Connected";
                status.ForeColor = Color.Green;
                startStop.Text = "Stop";
                isRunning = true;
     // if connection successful, send some data and start reading the socket
            }
            else
            {
                startStop.Text = "Start";
                client.DisconnectFromHost(AsyncErrorHandler);
                isRunning = false;
            }
        }
    }
}

我可以处理连接中的异常。现在我还需要处理成功的连接。

谢谢你。

4

2 回答 2

2

您可以遵循相同的模式,并提供一个在成功和错误时调用的处理程序:

class InternetConnector 
{ 
    private struct ConnectionData 
    { 
        public Action<Socket> SuccessHandler { get; set; } 
        public Action<Exception> ErrorHandler { get; set; } 
        public Socket Socket { get; set; } 
    } 

    public void ConnectToHost(Action<Socket> successHandler, Action<Exception> errorHandler) 
    { 
        IPEndPoint ip = new IPEndPoint(IPAddress.Parse(connector_host), connector_port); 
        client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
        var ConnectionData = new ConnectionData 
        { 
            SuccessHandler = successHandler,
            ErrorHandler = errorHandler, 
            Socket = client 
        }; 
        client.Blocking = true; 
        client.BeginConnect(ip, new AsyncCallback(ConnectCallback), connectionData); // <--  make sure to use the lower-case connectionData here!  :)
        connectDone.WaitOne(100); 
    } 

    private static void ConnectCallback(IAsyncResult ar) 
    { 
        ConnectionData connectionData = new ConnectionData(); 
        try 
        { 
            connectionData = (ConnectionData)ar.AsyncState; 
            connectionData.Socket.EndConnect(ar); 
            connectDone.Set(); 
            Connected = true; 
            if (connectionData.SuccessHandler != null)
                connectionData.SuccessHandler(connectionData.Socket);
        } 
        catch (Exception e) 
        { 
            if (connectionData.ErrorHandler != null) 
                connectionData.ErrorHandler(e); 
        } 
    } 
} 

作为成功处理程序传递的函数的签名必须与Action<Socket>委托匹配,这看起来像:

void MySuccessHandler(Socket socket) 
{ 
    // do stuff with the connected socket..        
    Console.WriteLine("Connected to {0}", socket.RemoteEndPoint);         
}

void MyErrorHandler(Exception e)
{
    Console.WriteLine("Connection error {0}", e.Message);         
}

...

myConnector.ConnectToHost(MySuccessHandler, MyErrorHandler);
于 2012-08-09T03:23:40.270 回答
0

也许这种扩展方法的一些变体可以激发灵感。它需要一个动作和一个时间跨度,并等待任务或超时之一首先完成。

如果超时赢得比赛,则执行提供的操作。

public static async Task<bool> OnTimeout<T>(this T t, Action<T> action, TimeSpan timespan) where T : Task
{
    var timeout = Task.Delay(timespan);

    if (await Task.WhenAny(t, timeout) == timeout)
    {
      //Enter here on timeout
      action(t);
      return true;
    }
    else
    {
      return false;
    }
}

像这样使用,在超时的情况下可以采取一些行动。

await socket.ConnectAsync().OnTimeout(t => {
  throw new TimeoutException();
}, TimeSpan.FromSeconds(5));  
于 2021-11-06T06:55:00.960 回答