gpt4 book ai didi

c# - 为什么我的表单在调用 BeginConnect 时卡住?

转载 作者:可可西里 更新时间:2023-11-01 02:53:10 25 4
gpt4 key购买 nike

我正在使用来自 Asynchronous Client Socket Example 的示例

using System;  
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;

// State object for receiving data from remote device.
public class StateObject {
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 256;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
}

public class AsynchronousClient {
// The port number for the remote device.
private const int port = 11000;

// ManualResetEvent instances signal completion.
private static ManualResetEvent connectDone =
new ManualResetEvent(false);
private static ManualResetEvent sendDone =
new ManualResetEvent(false);
private static ManualResetEvent receiveDone =
new ManualResetEvent(false);

// The response from the remote device.
private static String response = String.Empty;

private static void StartClient() {
// Connect to a remote device.
try {
// Establish the remote endpoint for the socket.
// The name of the
// remote device is "host.contoso.com".
IPHostEntry ipHostInfo = Dns.GetHostEntry("host.contoso.com");
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);

// Create a TCP/IP socket.
Socket client = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);

// Connect to the remote endpoint.
client.BeginConnect( remoteEP,
new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();

// Send test data to the remote device.
Send(client,"This is a test<EOF>");
sendDone.WaitOne();

// Receive the response from the remote device.
Receive(client);
receiveDone.WaitOne();

// Write the response to the console.
Console.WriteLine("Response received : {0}", response);

// Release the socket.
client.Shutdown(SocketShutdown.Both);
client.Close();

} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}

private static void ConnectCallback(IAsyncResult ar) {
try {
// Retrieve the socket from the state object.
Socket client = (Socket) ar.AsyncState;

// Complete the connection.
client.EndConnect(ar);

Console.WriteLine("Socket connected to {0}",
client.RemoteEndPoint.ToString());

// Signal that the connection has been made.
connectDone.Set();
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}

private static void Receive(Socket client) {
try {
// Create the state object.
StateObject state = new StateObject();
state.workSocket = client;

// Begin receiving the data from the remote device.
client.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}

private static void ReceiveCallback( IAsyncResult ar ) {
try {
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject state = (StateObject) ar.AsyncState;
Socket client = state.workSocket;

// Read data from the remote device.
int bytesRead = client.EndReceive(ar);

if (bytesRead > 0) {
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,bytesRead));

// Get the rest of the data.
client.BeginReceive(state.buffer,0,StateObject.BufferSize,0,
new AsyncCallback(ReceiveCallback), state);
} else {
// All the data has arrived; put it in response.
if (state.sb.Length > 1) {
response = state.sb.ToString();
}
// Signal that all bytes have been received.
receiveDone.Set();
}
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}

private static void Send(Socket client, String data) {
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);

// Begin sending the data to the remote device.
client.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), client);
}

private static void SendCallback(IAsyncResult ar) {
try {
// Retrieve the socket from the state object.
Socket client = (Socket) ar.AsyncState;

// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
Console.WriteLine("Sent {0} bytes to server.", bytesSent);

// Signal that all bytes have been sent.
sendDone.Set();
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}

public static int Main(String[] args) {
StartClient();
return 0;
}
}

我正在对我的应用程序的网络端进行编程,现在只是一些测试,但我遇到了一个奇怪的问题。当我调用 StartClient 方法时,我的 UI 卡住了。这个例子在一个单独的类中,只需在我的主窗体中调用它:AsynchronousClient.Startclient();

我需要提一下,现在没有服务器在监听,但为什么表单会卡住,毕竟我没有使用同步示例。我在互联网上读到这可能是因为表单线程必须从主线程运行,但我没有对此进行任何更改。在我看来,即使无法连接,表单也应该继续运行。

我如何实现这一目标?我可以给你我的代码,但我认为它不是很相关。就像我说的,我从 AsynchronousClient 类中调用 StartClient 方法,它是静态的,然后在我的主类中的某个地方调用它。 (现在在一个按钮中)。

我认为不相关,但我知道数据包已发送,我已经用 wireshark 检查过。

最佳答案

根据我的评论,AsynchronousClient.Startclient() 不是异步的,因为它使用 ManualResetEvent 来阻止。

我个人建议不要直接使用Socket。这实际上取决于您在做什么,但是有更好的 API 可用于远程通信。

HTTP、Json-RPC、gRPC、ZeroMQ 等...取决于您的用例。使用原始 TCP 套接字几乎总是矫枉过正。

无论如何,要使该方法真正异步,您必须摆脱 WaitOne 调用。
WaitOne 调用首先存在的原因,我相信,是为了使代码更具可读性,但理论上您可以在“连接”回调中执行“发送”逻辑并执行““发送”回调中的“接收”逻辑。

像这样

using System;  
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;

// State object for receiving data from remote device.
public class StateObject {
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 256;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
}

public class AsynchronousClient {
// The port number for the remote device.
private const int port = 11000;

// ManualResetEvent instances signal completion.
private static ManualResetEvent connectDone =
new ManualResetEvent(false);
private static ManualResetEvent sendDone =
new ManualResetEvent(false);
private static ManualResetEvent receiveDone =
new ManualResetEvent(false);

// The response from the remote device.
private static String response = String.Empty;

private static void StartClient() {
// Connect to a remote device.
try {
// Establish the remote endpoint for the socket.
// The name of the
// remote device is "host.contoso.com".
IPHostEntry ipHostInfo = Dns.GetHostEntry("host.contoso.com");
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);

// Create a TCP/IP socket.
Socket client = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);

// Connect to the remote endpoint.
client.BeginConnect( remoteEP,
new AsyncCallback(ConnectCallback), client);


} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}

private static void ConnectCallback(IAsyncResult ar) {
try {
// Retrieve the socket from the state object.
Socket client = (Socket) ar.AsyncState;

// Complete the connection.
client.EndConnect(ar);

Console.WriteLine("Socket connected to {0}",
client.RemoteEndPoint.ToString());

// we do it here now...
Send(client,"This is a test<EOF>");
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}

private static void Receive(Socket client) {
try {
// Create the state object.
StateObject state = new StateObject();
state.workSocket = client;

// Begin receiving the data from the remote device.
client.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}

private static void ReceiveCallback( IAsyncResult ar ) {
try {
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject state = (StateObject) ar.AsyncState;
Socket client = state.workSocket;

// Read data from the remote device.
int bytesRead = client.EndReceive(ar);

if (bytesRead > 0) {
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,bytesRead));

// Get the rest of the data.
client.BeginReceive(state.buffer,0,StateObject.BufferSize,0,
new AsyncCallback(ReceiveCallback), state);
} else {
// All the data has arrived; put it in response.
if (state.sb.Length > 1) {
response = state.sb.ToString();
}

// after all is done, we shut down the socket
client.Shutdown(SocketShutdown.Both);
client.Close();
}
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}

private static void Send(Socket client, String data) {
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);

// Begin sending the data to the remote device.
client.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), client);
}

private static void SendCallback(IAsyncResult ar) {
try {
// Retrieve the socket from the state object.
Socket client = (Socket) ar.AsyncState;

// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
Console.WriteLine("Sent {0} bytes to server.", bytesSent);

// We do it here now...
Receive(client);
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}

public static int Main(String[] args) {
StartClient();
return 0;
}
}

这应该有效。这样,StartClient 就不会阻塞。它在调用 BeginConnect 后立即返回。

但是,这是一个非常古老和肮脏的 API,这就是为什么我在使用 native Socket 之前会三思而后行。

你可以更好地解释你的目标,我会尝试提供更好的东西。

关于c# - 为什么我的表单在调用 BeginConnect 时卡住?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55189984/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com