我在 QUIC 上编写了这个基本服务器,它监听 2 个线程:
using System.Net;
using System.Net.Quic;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
namespace QuicServer
{
class Program
{
static async Task Main(string[] args)
{
bool isRunning = true;
X509Certificate2 serverCertificate = new X509Certificate2(@"C:\Users\sheud\source\repos\TESTQUICSERVER\certificate.pfx", "pswd");
if (!QuicListener.IsSupported)
{
Console.WriteLine("QUIC is not supported, check for presence of libmsquic and support of TLS 1.3.");
return;
}
var serverConnectionOptions = new QuicServerConnectionOptions
{
DefaultStreamErrorCode = 0x0A,
DefaultCloseErrorCode = 0x0B,
ServerAuthenticationOptions = new SslServerAuthenticationOptions
{
ApplicationProtocols = new List<SslApplicationProtocol>
{
new SslApplicationProtocol("threadone"),
new SslApplicationProtocol("threadtwo")
},
ServerCertificate = serverCertificate
}
};
var listener = await QuicListener.ListenAsync(new QuicListenerOptions
{
ListenEndPoint = new IPEndPoint(IPAddress.Any, 5555),
ApplicationProtocols = new List<SslApplicationProtocol>
{
new SslApplicationProtocol("threadone"),
new SslApplicationProtocol("threadtwo")
},
ConnectionOptionsCallback = (_, _, _) => ValueTask.FromResult(serverConnectionOptions)
});
Console.WriteLine("Server started...");
while (isRunning)
{
var connection = await listener.AcceptConnectionAsync();
Console.WriteLine($"Connection from {connection.RemoteEndPoint}");
_ = Task.Run(async () =>
{
try
{
var streamOne = await connection.AcceptInboundStreamAsync();
var streamTwo = await connection.AcceptInboundStreamAsync();
var readerOne = new StreamReader(streamOne);
var readerTwo = new StreamReader(streamTwo);
_ = Task.Run(async () =>
{
while (true)
{
var messageOne = await readerOne.ReadLineAsync();
if (messageOne == null) break;
Console.WriteLine($"Tunnel threadone received message: {messageOne}");
}
});
_ = Task.Run(async () =>
{
while (true)
{
var messageTwo = await readerTwo.ReadLineAsync();
if (messageTwo == null) break;
Console.WriteLine($"Tunnel threadtwo received message: {messageTwo}");
}
});
await Task.Delay(Timeout.Infinite);
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
});
}
}
}
}
还有一个客户端每秒向这两个线程发送消息:
using System.Net;
using System.Net.Quic;
using System.Net.Security;
namespace QuicClient
{
class Program
{
static async Task Main(string[] args)
{
bool isRunning = true;
if (!QuicConnection.IsSupported)
{
Console.WriteLine("QUIC is not supported, check for presence of libmsquic and support of TLS 1.3.");
return;
}
var clientConnectionOptions = new QuicClientConnectionOptions
{
RemoteEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5555),
DefaultStreamErrorCode = 0x0A,
DefaultCloseErrorCode = 0x0B,
MaxInboundUnidirectionalStreams = 10,
MaxInboundBidirectionalStreams = 100,
ClientAuthenticationOptions = new SslClientAuthenticationOptions
{
ApplicationProtocols = new List<SslApplicationProtocol>
{
new SslApplicationProtocol("threadone"),
new SslApplicationProtocol("threadtwo")
},
TargetHost = "localhost",
RemoteCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => true
}
};
QuicConnection? connection = null;
try
{
connection = await QuicConnection.ConnectAsync(clientConnectionOptions);
Console.WriteLine($"Connected {connection.LocalEndPoint} > {connection.RemoteEndPoint}");
var streamOne = await connection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional);
var streamTwo = await connection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional);
var writerOne = new StreamWriter(streamOne);
var writerTwo = new StreamWriter(streamTwo);
while (isRunning)
{
await writerOne.WriteLineAsync("message1");
await writerOne.FlushAsync();
await writerTwo.WriteLineAsync("message2");
await writerTwo.FlushAsync();
await Task.Delay(1000);
}
}
catch (Exception ex)
{
Console.WriteLine($"Error connecting: {ex}");
}
if (connection != null)
{
await connection.CloseAsync(0x0C);
await connection.DisposeAsync();
}
}
}
}
这段代码有效,但是当我尝试不通过 localhost 而是通过隧道连接(我使用 ngrok,它支持 TLS 1.3)时,连接未建立。替换:
RemoteEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5555),
在
RemoteEndPoint = new DnsEndPoint("4.tcp.eu.ngrok.io", 10956),
我在 中设置了 TargetHost 参数4.tcp.eu.ngrok.io,但是当我连接时,我陷入沉默,几秒钟后,我收到一条错误消息,指出超时已过期。我怀疑证书存在一些问题,我使用以下方法创建了它:
New-SelfSignedCertificate -DnsName $env:computername,localhost -FriendlyName MsQuic-Test -KeyUsageProperty Sign -KeyUsage DigitalSignature -CertStoreLocation cert:\CurrentUser\My -HashAlgorithm SHA256 -Provider "Microsoft Software Key Storage Provider" -KeyExportPolicy Exportable
但我不确定问题出在证书上,我尝试通过 WireShark 监听端口10956,但没有看到任何内容,甚至没有任何连接尝试,所以我不确定问题出在证书上