c# - 在接收命令时通过 TCP 发送字符串
问题描述
我正在开发一个阅读器程序。它基于 Winorms。
我需要一个代码,winform 将通过 TCP(端口 3573)按需发送一些数据。(通过需求,我的意思是当程序通过 TCP 接收命令 GET 时。
我是个新手,所以这个主题看起来很难将所有这些结合起来:线程、TCPRead TCP 发送、事件处理程序......
因此,我需要在这里获得有关如何实现它的完整代码或示例的帮助。
我尝试了一些来自互联网的示例代码,但没有一个有效(线程、TCPreader 和 TCPsender、TCPreaded 的事件处理)
在 TCP Reader 上,我们收到 GET,然后我们发送一些字符串,让 TCP Sender 说“hello world”
解决方案
套接字真的很难正确处理,而且 API 只是......令人讨厌。由于这只是要求错误,我将推荐使用“管道”API,它更符合现代async
代码并且更容易正确(并且在帧处理方面有更好的选择)。所以; 这是一个管道示例;
请注意,这需要 Pipelines.Sockets.Unofficial,它位于 nuget 上,通过:
<PackageReference Include="Pipelines.Sockets.Unofficial" Version="2.0.22" />
(添加它会自动添加您需要的所有其他部分)
using Pipelines.Sockets.Unofficial;
using System;
using System.IO.Pipelines;
using System.Net;
using System.Text;
using System.Threading.Tasks;
static class Program
{
static async Task Main()
{
var endpoint = new IPEndPoint(IPAddress.Loopback, 9042);
Console.WriteLine("[server] Starting server...");
using (var server = new MyServer())
{
server.Listen(endpoint);
Console.WriteLine("[server] Starting client...");
Task reader;
using (var client = await SocketConnection.ConnectAsync(endpoint))
{
reader = Task.Run(() => ShowIncomingDataAsync(client.Input));
await WriteAsync(client.Output, "hello");
await WriteAsync(client.Output, "world");
Console.WriteLine("press [return]");
Console.ReadLine();
}
await reader;
server.Stop();
}
}
private static async Task ShowIncomingDataAsync(PipeReader input)
{
try
{
while (true)
{
var read = await input.ReadAsync();
var buffer = read.Buffer;
if (buffer.IsEmpty && read.IsCompleted) break; // EOF
Console.WriteLine($"[client] Received {buffer.Length} bytes; marking consumed");
foreach (var segment in buffer)
{ // usually only one segment, but can be more complex
Console.WriteLine("[client] " + Program.GetAsciiString(segment.Span));
}
input.AdvanceTo(buffer.End); // "we ate it all"
}
}
catch { }
}
private static async Task WriteAsync(PipeWriter output, string payload)
{
var bytes = Encoding.ASCII.GetBytes(payload);
await output.WriteAsync(bytes);
}
internal static unsafe string GetAsciiString(ReadOnlySpan<byte> span)
{
fixed (byte* b = span)
{
return Encoding.ASCII.GetString(b, span.Length);
}
}
}
class MyServer : SocketServer
{
protected override Task OnClientConnectedAsync(in ClientConnection client)
=> RunClient(client);
private async Task RunClient(ClientConnection client)
{
Console.WriteLine($"[server] new client: {client.RemoteEndPoint}");
await ProcessRequests(client.Transport);
Console.WriteLine($"[server] ended client: {client.RemoteEndPoint}");
}
private async Task ProcessRequests(IDuplexPipe transport)
{
try
{
var input = transport.Input;
var output = transport.Output;
while (true)
{
var read = await input.ReadAsync();
var buffer = read.Buffer;
if (buffer.IsEmpty && read.IsCompleted) break; // EOF
Console.WriteLine($"[server] Received {buffer.Length} bytes; returning it, and marking consumed");
foreach (var segment in buffer)
{ // usually only one segment, but can be more complex
Console.WriteLine("[server] " + Program.GetAsciiString(segment.Span));
await output.WriteAsync(segment);
}
input.AdvanceTo(buffer.End); // "we ate it all"
}
}
catch { }
}
}
我可以用原始套接字来写这个,但是需要更多的代码来展示最佳实践并避免问题——所有这些丑陋已经隐藏在“管道”中。
输出:
[server] Starting server...
[server] Starting client...
[server] new client: 127.0.0.1:63076
press [return]
[server] Received 5 bytes; returning it, and marking consumed
[server] hello
[server] Received 5 bytes; returning it, and marking consumed
[client] Received 5 bytes; marking consumed
[client] hello
[server] world
[client] Received 5 bytes; marking consumed
[client] world
推荐阅读
- java - 是否可以使用 Java 反射从注入的 DEX 中获取应用程序的类对象?
- python - 删除标点符号后从文本文件中打印唯一单词列表,并找到最长的单词
- ios - 为什么我的导航控制器的动画类型会发生变化?
- python - 二分搜索在我的 python 代码中不起作用
- linux - 如何将命令的输出获取到变量中?
- pandas - HoloViews:为 pandas 数据框中的每一列创建箱线图
- r - 如何逐块栅格化 sf 几何?
- r - group_by,根据名称对不同的列使用不同的函数
- reactjs - javascript - 即使在卸载/强制上下文丢失后也能在浏览器缓存中保持加载的 gltf
- c++ - 如何使用ifstream检查文件中变量的类型?