gpt4 book ai didi

c# - .Net Core 中的异步服务器套接字 - 如何返回结果?

转载 作者:行者123 更新时间:2023-12-04 01:22:52 24 4
gpt4 key购买 nike

我需要通过 TCP 异步发送数据。它是字符串的集合 ICollection<string> .

我搜索并找到了一个很好的 starting example from Microsoft (见下文)。样本似乎在 .NET Framework 下, 但我认为它适用于 .NET Core

我在做什么:

  1. 我将代码重新用作非静态

  2. 我想发送一个字符串集合ICollection<string> .我知道我可以重写它以在 main 方法中发送字符串集合。没问题。

  3. 我希望收到对发送的每条消息的响应并对其进行处理。当前响应静态存储在 private static String response = String.Empty; 中.我不希望它是静态的。我想要一个本地方法变量。

  4. 我的挑战从项目 3. 开始。如何返回似乎只能从 private static void ReceiveCallback( IAsyncResult ar ) 中访问的响应消息

    我不认为将其更改为 private static string ReceiveCallback( IAsyncResult ar )会工作。如果是这样,我如何从 client.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state); 中读取它? ?

我在一个非常古老的帖子上悬赏了 300 点,因为我发现了一个类似的问题:C# Asyn. Socket Programming .很高兴奖励在这里和那里回答问题的任何人。

另一个问题是:打开一个 TCP 连接,发送多条消息,然后关闭它是推荐的做法吗?或者为每条发送的消息打开一个 TCP 连接?

微软示例

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. <------ ### the response data that I want to access, non statically
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); //<------ The receive callback is here, how do I return the result to the caller?
} 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(); //<--------- ### Where it is assigned, I want it returned
}
// 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;
}
}

最佳答案

我从 .NET Core 团队找到了答案。据他们说:

关于 Microsoft Example :

That's actually not a good example, because it uses the outdated Begin*/End* pattern (also known as APM). Instead, you should use using async-await.

And if you switched to that, it would make changing the code the way you want much easier, because there aren't any callbacks anymore, instead you do e.g. await client.ReceiveAsync(…) and, after processing the response, return the result.

https://github.com/dotnet/core/issues/4828#issuecomment-643619106

推荐的做法如下:

ICollection<string> strings = ...;
using Socket socket = ...;
using var stream = new NetworkStream(socket);
using var writer = new StreamWriter(stream);

foreach(string s in strings)
{
await writer.WriteLineAsync(s);
}
await writer.FlushAsync();

添加注释:

If your strings contain newlines, you will want to length-prefix your messages or escape the newlines prior to writing them.

对于我的问题:打开一个 TCP 连接,发送多条消息,然后关闭它是推荐的做法吗?或者为每条发送的消息打开一个 TCP 连接?

Establishing a TCP connection is generally a lot more expensive than using an existing one. But, this is ultimately scenario-dependent and you will want to do some more learning and prototyping here to see what is right for you.

https://github.com/dotnet/core/issues/4828#issuecomment-643694377

关于c# - .Net Core 中的异步服务器套接字 - 如何返回结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62351485/

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