This commit is contained in:
snltty
2025-03-26 00:16:31 +08:00
parent 777234fb60
commit 72af4e529d
37 changed files with 277 additions and 116 deletions

View File

@@ -35,7 +35,7 @@ jobs:
release_name: v1.7.1.${{ steps.date.outputs.today }} release_name: v1.7.1.${{ steps.date.outputs.today }}
draft: false draft: false
prerelease: false prerelease: false
body: "1. 优化数据同步\r\n2. 优化linux网卡,我感觉网卡速度比较正常了\r\n3. 建议更新" body: "1. 优化数据同步\r\n2. 优化linux的tun网卡网卡读写分离提高性能\r\n3. 优化windows网卡的禁用自动启用\r\n4. 增加TCP包合并。网卡IP包多个合并一起发送\r\n5. 建议更新"
- name: publish projects - name: publish projects
run: ./publish.bat run: ./publish.bat
- name: upload-win-x86-oss - name: upload-win-x86-oss

View File

@@ -96,7 +96,7 @@ namespace linker.app
{ {
base.OnCreate(); base.OnCreate();
string name = string.IsNullOrWhiteSpace(tuntapConfigTransfer.Info.Name) ? "linker" : tuntapConfigTransfer.Info.Name; string name = string.IsNullOrWhiteSpace(tuntapConfigTransfer.Info.Name) ? "linker" : tuntapConfigTransfer.Info.Name;
adapter.Setup(name, tuntapConfigTransfer.Info.IP, tuntapConfigTransfer.Info.PrefixLength, 1420); tuntapTransfer.Setup(name, tuntapConfigTransfer.Info.IP, tuntapConfigTransfer.Info.PrefixLength);
} }
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId) public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{ {
@@ -112,13 +112,6 @@ namespace linker.app
public async Task Callback(LinkerTunDevicPacket packet) public async Task Callback(LinkerTunDevicPacket packet)
{ {
if (packet.IPV4Broadcast || packet.IPV6Multicast)
{
if ((tuntapConfigTransfer.Switch & TuntapSwitch.Multicast) == TuntapSwitch.Multicast)
{
return;
}
}
await tuntapProxy.InputPacket(packet).ConfigureAwait(false); await tuntapProxy.InputPacket(packet).ConfigureAwait(false);
} }
public async ValueTask Close(ITunnelConnection connection) public async ValueTask Close(ITunnelConnection connection)
@@ -366,7 +359,7 @@ namespace linker.app
} }
*/ */
} }
public async Task<bool> CheckAvailable() public async Task<bool> CheckAvailable(bool order = false)
{ {
return await Task.FromResult(fd > 0); return await Task.FromResult(fd > 0);
} }

View File

@@ -0,0 +1,7 @@
---
sidebar_position: 12
---
# 12、在线讨论咨询
<a href="https://jq.qq.com/?_wv=1027&k=ucoIVfz4" target="_blank">你可以加入QQ群1121552990</a>

View File

@@ -1,7 +1,7 @@
--- ---
sidebar_position: 12 sidebar_position: 13
--- ---
# 12、公益赞助 # 13、公益赞助
![Docusaurus Plushie](./img/qr.jpg) ![Docusaurus Plushie](./img/qr.jpg)

View File

@@ -18,7 +18,6 @@ using linker.messenger.updater;
using linker.messenger.store.file; using linker.messenger.store.file;
using linker.messenger.serializer.memorypack; using linker.messenger.serializer.memorypack;
using linker.libs; using linker.libs;
using System;
namespace linker.messenger.entry namespace linker.messenger.entry
{ {

View File

@@ -93,6 +93,7 @@ namespace linker.messenger.store.file
serviceCollection.AddSingleton<ITuntapClientStore, TuntapClientStore>(); serviceCollection.AddSingleton<ITuntapClientStore, TuntapClientStore>();
serviceCollection.AddSingleton<ILeaseServerStore, LeaseServerStore>(); serviceCollection.AddSingleton<ILeaseServerStore, LeaseServerStore>();
serviceCollection.AddSingleton<ILeaseClientStore, LeaseClientStore>();
return serviceCollection; return serviceCollection;
} }

View File

@@ -27,18 +27,18 @@ namespace linker.messenger.store.file
database = new LiteDatabase(new ConnectionString($"Filename={db}; Password={Helper.GlobalString}; journal=false"), bsonMapper); database = new LiteDatabase(new ConnectionString($"Filename={db}; Password={Helper.GlobalString}; journal=false"), bsonMapper);
CheckpointTask(); if (OperatingSystem.IsAndroid() == false)
{
AppDomain.CurrentDomain.ProcessExit += (s, e) => { database.Checkpoint(); database.Dispose(); };
Console.CancelKeyPress += (s, e) => { database.Checkpoint(); database.Dispose(); };
}
TimerHelper.SetIntervalLong(database.Checkpoint, 3000);
} }
public ILiteCollection<T> GetCollection<T>(string name) public ILiteCollection<T> GetCollection<T>(string name)
{ {
return database.GetCollection<T>(name); return database.GetCollection<T>(name);
} }
private void CheckpointTask()
{
TimerHelper.SetIntervalLong(database.Checkpoint, 3000);
}
} }
} }

View File

@@ -1,4 +1,6 @@
using linker.messenger.tuntap; using linker.messenger.tuntap;
using linker.messenger.tuntap.lease;
using System.Collections.Concurrent;
namespace linker.messenger.store.file namespace linker.messenger.store.file
{ {
@@ -8,5 +10,6 @@ namespace linker.messenger.store.file
/// 虚拟网卡配置 /// 虚拟网卡配置
/// </summary> /// </summary>
public TuntapConfigInfo Tuntap { get; set; } = new TuntapConfigInfo(); public TuntapConfigInfo Tuntap { get; set; } = new TuntapConfigInfo();
public ConcurrentDictionary<string, LeaseInfo> Leases { get; set; } = new ConcurrentDictionary<string, LeaseInfo>();
} }
} }

View File

@@ -0,0 +1,37 @@
using linker.messenger.tuntap;
using linker.messenger.tuntap.lease;
namespace linker.messenger.store.file.tuntap
{
public sealed class LeaseClientStore : ILeaseClientStore
{
public TuntapConfigInfo Info => runningConfig.Data.Tuntap;
private readonly RunningConfig runningConfig;
public LeaseClientStore(RunningConfig runningConfig)
{
this.runningConfig = runningConfig;
}
public LeaseInfo Get(string key)
{
if (runningConfig.Data.Leases.TryGetValue(key, out LeaseInfo info))
{
return info;
}
return new LeaseInfo();
}
public bool Set(string key, LeaseInfo info)
{
runningConfig.Data.Leases.AddOrUpdate(key, info, (a, b) => info);
return true;
}
public void Confirm()
{
runningConfig.Data.Update();
}
}
}

View File

@@ -1,5 +1,4 @@
using linker.libs; using System.Collections.Concurrent;
using System.Collections.Concurrent;
using System.Net; using System.Net;
namespace linker.messenger.tuntap namespace linker.messenger.tuntap
@@ -41,7 +40,18 @@ namespace linker.messenger.tuntap
public ConcurrentDictionary<string, TuntapGroup2IPInfo> Group2IP { get; set; } = new ConcurrentDictionary<string, TuntapGroup2IPInfo>(); public ConcurrentDictionary<string, TuntapGroup2IPInfo> Group2IP { get; set; } = new ConcurrentDictionary<string, TuntapGroup2IPInfo>();
public bool DisableNat => (Switch & TuntapSwitch.DisableNat) == TuntapSwitch.DisableNat; /// <summary>
/// 禁用nat
/// </summary>
public bool DisableNat => Switch.HasFlag(TuntapSwitch.DisableNat);
/// <summary>
/// tcp包合并
/// </summary>
public bool TcpMerge => Switch.HasFlag(TuntapSwitch.TcpMerge);
/// <summary>
/// 调整网卡顺序
/// </summary>
public bool InterfaceOrder => Switch.HasFlag(TuntapSwitch.InterfaceOrder);
} }
public sealed class TuntapGroup2IPInfo public sealed class TuntapGroup2IPInfo
@@ -258,6 +268,48 @@ namespace linker.messenger.tuntap
} }
} }
} }
/// <summary>
/// tcp包合并
/// </summary>
public bool TcpMerge
{
get
{
return (Switch & TuntapSwitch.TcpMerge) == TuntapSwitch.TcpMerge;
}
set
{
if (value)
{
Switch |= TuntapSwitch.TcpMerge;
}
else
{
Switch &= ~TuntapSwitch.TcpMerge;
}
}
}
/// <summary>
/// 调整网卡顺序
/// </summary>
public bool InterfaceOrder
{
get
{
return (Switch & TuntapSwitch.InterfaceOrder) == TuntapSwitch.InterfaceOrder;
}
set
{
if (value)
{
Switch |= TuntapSwitch.InterfaceOrder;
}
else
{
Switch &= ~TuntapSwitch.InterfaceOrder;
}
}
}
} }
public sealed partial class TuntapForwardInfo public sealed partial class TuntapForwardInfo
@@ -335,6 +387,14 @@ namespace linker.messenger.tuntap
/// 禁用Nat /// 禁用Nat
/// </summary> /// </summary>
DisableNat = 32, DisableNat = 32,
/// <summary>
/// 启用小包合并
/// </summary>
TcpMerge = 64,
/// <summary>
/// 调整网卡顺序
/// </summary>
InterfaceOrder = 128,
} }
} }

View File

@@ -96,7 +96,7 @@ namespace linker.messenger.tuntap
await RetstartDevice().ConfigureAwait(false); await RetstartDevice().ConfigureAwait(false);
return; return;
} }
if (await tuntapTransfer.CheckAvailable().ConfigureAwait(false) == false) if (await tuntapTransfer.CheckAvailable(tuntapConfigTransfer.Info.InterfaceOrder).ConfigureAwait(false) == false)
{ {
tuntapTransfer.Refresh(); tuntapTransfer.Refresh();
} }
@@ -112,13 +112,6 @@ namespace linker.messenger.tuntap
public async Task Callback(LinkerTunDevicPacket packet) public async Task Callback(LinkerTunDevicPacket packet)
{ {
if (packet.IPV4Broadcast || packet.IPV6Multicast)
{
if ((tuntapConfigTransfer.Switch & TuntapSwitch.Multicast) == TuntapSwitch.Multicast)
{
return;
}
}
await tuntapProxy.InputPacket(packet).ConfigureAwait(false); await tuntapProxy.InputPacket(packet).ConfigureAwait(false);
} }
public async ValueTask Close(ITunnelConnection connection) public async ValueTask Close(ITunnelConnection connection)

View File

@@ -48,7 +48,7 @@ namespace linker.messenger.tuntap
if (tuntapTransfer.Status == TuntapStatus.Running && tuntapConfigTransfer.Switch.HasFlag(TuntapSwitch.ShowDelay)) if (tuntapTransfer.Status == TuntapStatus.Running && tuntapConfigTransfer.Switch.HasFlag(TuntapSwitch.ShowDelay))
{ {
var items = tuntapDecenter.Infos.Values.Where(c => c.IP != null && c.IP.Equals(IPAddress.Any) == false && (c.Status & TuntapStatus.Running) == TuntapStatus.Running); var items = tuntapDecenter.Infos.Values.Where(c => c.IP != null && c.IP.Equals(IPAddress.Any) == false && (c.Status & TuntapStatus.Running) == TuntapStatus.Running);
if ((tuntapConfigTransfer.Switch & TuntapSwitch.AutoConnect) != TuntapSwitch.AutoConnect) if (tuntapConfigTransfer.Switch.HasFlag(TuntapSwitch.AutoConnect) == false)
{ {
var connections = tuntapProxy.GetConnections(); var connections = tuntapProxy.GetConnections();
items = items.Where(c => connections.TryGetValue(c.MachineId, out ITunnelConnection connection) && connection.Connected || c.MachineId == signInClientStore.Id); items = items.Where(c => connections.TryGetValue(c.MachineId, out ITunnelConnection connection) && connection.Connected || c.MachineId == signInClientStore.Id);

View File

@@ -27,16 +27,21 @@ namespace linker.messenger.tuntap
private readonly OperatingMultipleManager operatingMultipleManager = new OperatingMultipleManager(); private readonly OperatingMultipleManager operatingMultipleManager = new OperatingMultipleManager();
protected override string TransactionId => "tuntap"; protected override string TransactionId => "tuntap";
private readonly TuntapConfigTransfer tuntapConfigTransfer;
public TuntapProxy(ISignInClientStore signInClientStore, public TuntapProxy(ISignInClientStore signInClientStore,
TunnelTransfer tunnelTransfer, RelayClientTransfer relayTransfer, PcpTransfer pcpTransfer, TunnelTransfer tunnelTransfer, RelayClientTransfer relayTransfer, PcpTransfer pcpTransfer,
SignInClientTransfer signInClientTransfer, IRelayClientStore relayClientStore) SignInClientTransfer signInClientTransfer, IRelayClientStore relayClientStore, TuntapConfigTransfer tuntapConfigTransfer)
: base(tunnelTransfer, relayTransfer, pcpTransfer, signInClientTransfer, signInClientStore, relayClientStore) : base(tunnelTransfer, relayTransfer, pcpTransfer, signInClientTransfer, signInClientStore, relayClientStore)
{ {
this.tuntapConfigTransfer = tuntapConfigTransfer;
} }
protected override void Connected(ITunnelConnection connection) protected override void Connected(ITunnelConnection connection)
{ {
connection.BeginReceive(this, null); connection.BeginReceive(this, null);
if (tuntapConfigTransfer.Info.TcpMerge)
connection.StartPacketMerge();
//有哪些目标IP用了相同目标隧道更新一下 //有哪些目标IP用了相同目标隧道更新一下
List<uint> keys = ipConnections.Where(c => c.Value.RemoteMachineId == connection.RemoteMachineId).Select(c => c.Key).ToList(); List<uint> keys = ipConnections.Where(c => c.Value.RemoteMachineId == connection.RemoteMachineId).Select(c => c.Key).ToList();
foreach (uint ip in keys) foreach (uint ip in keys)
@@ -80,7 +85,7 @@ namespace linker.messenger.tuntap
//IPV4广播组播、IPV6 多播 //IPV4广播组播、IPV6 多播
if (packet.IPV4Broadcast || packet.IPV6Multicast) if (packet.IPV4Broadcast || packet.IPV6Multicast)
{ {
if (connections.IsEmpty == false) if (tuntapConfigTransfer.Switch.HasFlag(TuntapSwitch.Multicast) == false && connections.IsEmpty == false)
{ {
await Task.WhenAll(connections.Values.Where(c => c != null && c.Connected).Select(c => c.SendAsync(packet.Buffer, packet.Offset, packet.Length))); await Task.WhenAll(connections.Values.Where(c => c != null && c.Connected).Select(c => c.SendAsync(packet.Buffer, packet.Offset, packet.Length)));
} }
@@ -119,6 +124,12 @@ namespace linker.messenger.tuntap
/// <returns></returns> /// <returns></returns>
private async Task<ITunnelConnection> ConnectTunnel(uint ip) private async Task<ITunnelConnection> ConnectTunnel(uint ip)
{ {
/*
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
Console.WriteLine($"tuntap connect to {NetworkHelper.ToIP(ip)}");
}
*/
if (cidrManager.FindValue(ip, out string machineId)) if (cidrManager.FindValue(ip, out string machineId))
{ {
return await ConnectTunnel(machineId, TunnelProtocolType.Quic).ConfigureAwait(false); return await ConnectTunnel(machineId, TunnelProtocolType.Quic).ConfigureAwait(false);

View File

@@ -181,9 +181,9 @@ namespace linker.messenger.tuntap
{ {
linkerTunDeviceAdapter.DelRoute(ips); linkerTunDeviceAdapter.DelRoute(ips);
} }
public async Task<bool> CheckAvailable() public async Task<bool> CheckAvailable(bool order = false)
{ {
return await linkerTunDeviceAdapter.CheckAvailable().ConfigureAwait(false); return await linkerTunDeviceAdapter.CheckAvailable(order).ConfigureAwait(false);
} }
} }
} }

View File

@@ -0,0 +1,9 @@
namespace linker.messenger.tuntap.lease
{
public interface ILeaseClientStore
{
public LeaseInfo Get(string key);
public bool Set(string key,LeaseInfo info);
public void Confirm();
}
}

View File

@@ -11,16 +11,23 @@ namespace linker.messenger.tuntap.lease
private readonly IMessengerSender messengerSender; private readonly IMessengerSender messengerSender;
private readonly SignInClientState signInClientState; private readonly SignInClientState signInClientState;
private readonly ISerializer serializer; private readonly ISerializer serializer;
public LeaseClientTreansfer(IMessengerSender messengerSender, SignInClientState signInClientState, ISerializer serializer) private readonly ILeaseClientStore leaseClientStore;
private readonly ISignInClientStore signInClientStore;
public LeaseClientTreansfer(IMessengerSender messengerSender, SignInClientState signInClientState, ISerializer serializer, ILeaseClientStore leaseClientStore, ISignInClientStore signInClientStore)
{ {
this.messengerSender = messengerSender; this.messengerSender = messengerSender;
this.signInClientState = signInClientState; this.signInClientState = signInClientState;
this.serializer = serializer; this.serializer = serializer;
this.leaseClientStore = leaseClientStore;
this.signInClientStore = signInClientStore;
LeaseExpTask(); LeaseExpTask();
} }
public async Task AddNetwork(LeaseInfo info) public async Task AddNetwork(LeaseInfo info)
{ {
leaseClientStore.Set(signInClientStore.Group.Id, info);
leaseClientStore.Confirm();
await messengerSender.SendOnly(new MessageRequestWrap await messengerSender.SendOnly(new MessageRequestWrap
{ {
Connection = signInClientState.Connection, Connection = signInClientState.Connection,
@@ -39,6 +46,8 @@ namespace linker.messenger.tuntap.lease
if (resp.Code == MessageResponeCodes.OK) if (resp.Code == MessageResponeCodes.OK)
{ {
LeaseInfo info = serializer.Deserialize<LeaseInfo>(resp.Data.Span); LeaseInfo info = serializer.Deserialize<LeaseInfo>(resp.Data.Span);
leaseClientStore.Set(signInClientStore.Group.Id, info);
leaseClientStore.Confirm();
return info; return info;
} }
return new LeaseInfo { IP = IPAddress.Any, PrefixLength = 24 }; return new LeaseInfo { IP = IPAddress.Any, PrefixLength = 24 };
@@ -74,6 +83,25 @@ namespace linker.messenger.tuntap.lease
private void LeaseExpTask() private void LeaseExpTask()
{ {
signInClientState.OnSignInSuccess += async (times) =>
{
try
{
await GetNetwork().ConfigureAwait(false);
LeaseInfo info = leaseClientStore.Get(signInClientStore.Group.Id);
if (info != null && info.IP.Equals(IPAddress.Any) == false)
{
await AddNetwork(info);
}
}
catch (Exception ex)
{
if(LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
LoggerHelper.Instance.Error(ex);
}
}
};
TimerHelper.SetIntervalLong(async () => TimerHelper.SetIntervalLong(async () =>
{ {
await messengerSender.SendReply(new MessageRequestWrap await messengerSender.SendReply(new MessageRequestWrap
@@ -81,7 +109,7 @@ namespace linker.messenger.tuntap.lease
Connection = signInClientState.Connection, Connection = signInClientState.Connection,
MessengerId = (ushort)TuntapMessengerIds.LeaseExp, MessengerId = (ushort)TuntapMessengerIds.LeaseExp,
}).ConfigureAwait(false); }).ConfigureAwait(false);
}, 60000); }, 60000);
} }
} }
} }

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<project ver="10" name="linker.tray.win" libEmbed="true" icon="..\linker\favicon.ico" ui="win" output="linker.tray.win.exe" CompanyName="snltty" FileDescription="linker.tray.win" LegalCopyright="Copyright (C) snltty 2024" ProductName="linker.tray.win" InternalName="linker.install.win" FileVersion="0.0.0.230" ProductVersion="0.0.0.230" publishDir="/dist/" dstrip="false" local="false" ignored="false"> <project ver="10" name="linker.tray.win" libEmbed="true" icon="..\linker\favicon.ico" ui="win" output="linker.tray.win.exe" CompanyName="snltty" FileDescription="linker.tray.win" LegalCopyright="Copyright (C) snltty 2024" ProductName="linker.tray.win" InternalName="linker.install.win" FileVersion="0.0.0.231" ProductVersion="0.0.0.231" publishDir="/dist/" dstrip="false" local="false" ignored="false">
<file name="main.aardio" path="main.aardio" comment="main.aardio"/> <file name="main.aardio" path="main.aardio" comment="main.aardio"/>
<folder name="资源文件" path="res" embed="true" local="false" ignored="false"> <folder name="资源文件" path="res" embed="true" local="false" ignored="false">
<file name="favicon.ico" path="res\favicon.ico" comment="res\favicon.ico"/> <file name="favicon.ico" path="res\favicon.ico" comment="res\favicon.ico"/>

Binary file not shown.

View File

@@ -1 +1 @@
.table-sort th[data-v-754b053a]{border-bottom:0}.dropdown[data-v-2f0ed5e0]{border:1px solid #ddd;padding:.4rem;font-size:1.3rem;border-radius:.4rem;position:relative}.dropdown .el-icon[data-v-2f0ed5e0]{vertical-align:middle}.dropdown .badge[data-v-2f0ed5e0]{position:absolute;right:-1rem;top:-50%;border-radius:10px;background-color:#f1ae05;color:#fff;padding:.2rem .6rem;font-size:1.2rem}a[data-v-56c0e8be]{color:#666;text-decoration:underline}a.green[data-v-56c0e8be]{color:green;font-weight:700}a.download[data-v-56c0e8be]{margin-left:.6rem}a.download .el-icon[data-v-56c0e8be]{vertical-align:middle;font-weight:700;margin-left:.3rem}a.download .el-icon.loading[data-v-56c0e8be]{animation:loading-56c0e8be 1s linear infinite}a.download+a.download[data-v-56c0e8be]{margin-left:.2rem}@keyframes loading-56c0e8be{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}img.system[data-v-9f58a72e]{height:1.6rem;vertical-align:middle;margin-right:.4rem}.self[data-v-9f58a72e]{color:#d400ff}.self .el-icon[data-v-9f58a72e]{vertical-align:text-bottom}.ipaddress span[data-v-5db71b03]{vertical-align:middle}.el-input[data-v-5db71b03]{width:12rem;margin-right:.6rem}.el-col[data-v-7a697708]{text-align:left}div.point[data-v-41d1beca]{margin:-.2rem .3rem 0 -1.3rem;position:absolute}span.point[data-v-41d1beca]{width:.8rem;height:.8rem;border-radius:50%;display:inline-block;vertical-align:middle;background-color:#eee;border:1px solid #ddd;cursor:pointer;transition:.3s}span.point[data-v-41d1beca]:hover{transform:scale(2)}span.point.p2p[data-v-41d1beca]{background-color:#01c901;border:1px solid #049538}span.point.relay[data-v-41d1beca]{background-color:#e3e811;border:1px solid #b3c410}span.point.node[data-v-41d1beca]{background-color:#09dda9;border:1px solid #0cac90}.el-icon.loading[data-v-5ce8d590],a.loading[data-v-5ce8d590]{vertical-align:middle;font-weight:700;animation:loading-5ce8d590 1s linear infinite}.el-switch.is-disabled[data-v-5ce8d590]{opacity:1}.el-input[data-v-5ce8d590]{width:8rem}.delay[data-v-5ce8d590]{position:absolute;right:0;bottom:0;line-height:normal}.switch-btn[data-v-5ce8d590]{font-size:1.5rem}.any[data-v-5ce8d590]{position:absolute;left:-7px;top:-2px;line-height:normal}.any.green[data-v-5ce8d590]{background:linear-gradient(270deg,#caff00,green,#0d6d23,#e38a00,green);background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:hsla(0,0%,100%,0)}@keyframes loading-5ce8d590{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.wrap[data-v-786fe646]{padding-right:1rem}.remark[data-v-786fe646]{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.wrap[data-v-286c7cac]{padding-right:1rem}.el-switch.is-disabled[data-v-0b701835]{opacity:1}.upgrade-wrap[data-v-0b701835]{border:1px solid #ddd;margin-bottom:2rem;padding:0 0 1rem 0}.el-switch.is-disabled[data-v-67ed3552]{opacity:1}.calc span[data-v-67ed3552]{display:inline-block}.calc span.label[data-v-67ed3552]{width:6rem}.el-icon.loading[data-v-3a4bfe6c],a.loading[data-v-3a4bfe6c]{vertical-align:middle;font-weight:700;animation:loading-3a4bfe6c 1s linear infinite}.el-switch.is-disabled[data-v-3a4bfe6c]{opacity:1}.el-input[data-v-3a4bfe6c]{width:8rem}.switch-btn[data-v-3a4bfe6c]{font-size:1.5rem}@keyframes loading-3a4bfe6c{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.el-switch.is-disabled[data-v-022e3781]{opacity:1}.upgrade-wrap[data-v-022e3781]{border:1px solid #ddd;margin-bottom:2rem;padding:1rem 0 1rem 0}.lan-item[data-v-022e3781]{margin-bottom:0}.el-switch.is-disabled[data-v-64b81c5b]{opacity:1}.green[data-v-64b81c5b]{font-weight:700}img.system[data-v-64b81c5b]{height:1.4rem;margin-right:.4rem;border:1px solid #eee}.el-switch.is-disabled[data-v-6941c158]{opacity:1}ul li[data-v-6941c158]{padding-left:2rem}a[data-v-2ee190a4]{text-decoration:underline}a+a[data-v-2ee190a4]{margin-left:1rem}a.green[data-v-2ee190a4]{font-weight:700}.head[data-v-6897ed85]{padding-bottom:1rem}.green[data-v-6897ed85]{color:green;font-weight:700}.error[data-v-6897ed85]{font-weight:700}.error .el-icon[data-v-6897ed85]{vertical-align:text-bottom}.head[data-v-7d65167d]{padding-bottom:1rem}.error[data-v-7d65167d]{font-weight:700}.error .el-icon[data-v-7d65167d]{vertical-align:text-bottom}.head[data-v-8c388c86]{padding-bottom:1rem}.blue[data-v-8c388c86]{color:#409eff}.dropdown[data-v-8c388c86]{border:1px solid #ddd;padding:.4rem;font-size:1.3rem;border-radius:.4rem;position:relative}.dropdown .el-icon[data-v-8c388c86]{vertical-align:middle}.dropdown .badge[data-v-8c388c86]{position:absolute;right:-1rem;top:-50%;border-radius:10px;background-color:#f1ae05;color:#fff;padding:.2rem .6rem;font-size:1.2rem}.table-sort.el-table th.el-table__cell.is-leaf{border-bottom:0}.table-sort.el-table .el-table__inner-wrapper:before{height:0}.home-list-wrap[data-v-4766ad40]{padding:1rem}.home-list-wrap .page[data-v-4766ad40]{padding-top:1rem}.home-list-wrap .page-wrap[data-v-4766ad40]{display:inline-block} .table-sort th[data-v-754b053a]{border-bottom:0}.dropdown[data-v-2f0ed5e0]{border:1px solid #ddd;padding:.4rem;font-size:1.3rem;border-radius:.4rem;position:relative}.dropdown .el-icon[data-v-2f0ed5e0]{vertical-align:middle}.dropdown .badge[data-v-2f0ed5e0]{position:absolute;right:-1rem;top:-50%;border-radius:10px;background-color:#f1ae05;color:#fff;padding:.2rem .6rem;font-size:1.2rem}a[data-v-56c0e8be]{color:#666;text-decoration:underline}a.green[data-v-56c0e8be]{color:green;font-weight:700}a.download[data-v-56c0e8be]{margin-left:.6rem}a.download .el-icon[data-v-56c0e8be]{vertical-align:middle;font-weight:700;margin-left:.3rem}a.download .el-icon.loading[data-v-56c0e8be]{animation:loading-56c0e8be 1s linear infinite}a.download+a.download[data-v-56c0e8be]{margin-left:.2rem}@keyframes loading-56c0e8be{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}img.system[data-v-9f58a72e]{height:1.6rem;vertical-align:middle;margin-right:.4rem}.self[data-v-9f58a72e]{color:#d400ff}.self .el-icon[data-v-9f58a72e]{vertical-align:text-bottom}.ipaddress span[data-v-5db71b03]{vertical-align:middle}.el-input[data-v-5db71b03]{width:12rem;margin-right:.6rem}.el-col[data-v-7a697708]{text-align:left}div.point[data-v-41d1beca]{margin:-.2rem .3rem 0 -1.3rem;position:absolute}span.point[data-v-41d1beca]{width:.8rem;height:.8rem;border-radius:50%;display:inline-block;vertical-align:middle;background-color:#eee;border:1px solid #ddd;cursor:pointer;transition:.3s}span.point[data-v-41d1beca]:hover{transform:scale(2)}span.point.p2p[data-v-41d1beca]{background-color:#01c901;border:1px solid #049538}span.point.relay[data-v-41d1beca]{background-color:#e3e811;border:1px solid #b3c410}span.point.node[data-v-41d1beca]{background-color:#09dda9;border:1px solid #0cac90}.el-icon.loading[data-v-5ce8d590],a.loading[data-v-5ce8d590]{vertical-align:middle;font-weight:700;animation:loading-5ce8d590 1s linear infinite}.el-switch.is-disabled[data-v-5ce8d590]{opacity:1}.el-input[data-v-5ce8d590]{width:8rem}.delay[data-v-5ce8d590]{position:absolute;right:0;bottom:0;line-height:normal}.switch-btn[data-v-5ce8d590]{font-size:1.5rem}.any[data-v-5ce8d590]{position:absolute;left:-7px;top:-2px;line-height:normal}.any.green[data-v-5ce8d590]{background:linear-gradient(270deg,#caff00,green,#0d6d23,#e38a00,green);background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:hsla(0,0%,100%,0)}@keyframes loading-5ce8d590{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.wrap[data-v-786fe646]{padding-right:1rem}.remark[data-v-786fe646]{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.wrap[data-v-286c7cac]{padding-right:1rem}.el-switch.is-disabled[data-v-d52cdcd0]{opacity:1}.upgrade-wrap[data-v-d52cdcd0]{border:1px solid #ddd;margin-bottom:2rem;padding:0 0 1rem 0}.el-switch.is-disabled[data-v-67ed3552]{opacity:1}.calc span[data-v-67ed3552]{display:inline-block}.calc span.label[data-v-67ed3552]{width:6rem}.el-icon.loading[data-v-3a4bfe6c],a.loading[data-v-3a4bfe6c]{vertical-align:middle;font-weight:700;animation:loading-3a4bfe6c 1s linear infinite}.el-switch.is-disabled[data-v-3a4bfe6c]{opacity:1}.el-input[data-v-3a4bfe6c]{width:8rem}.switch-btn[data-v-3a4bfe6c]{font-size:1.5rem}@keyframes loading-3a4bfe6c{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.el-switch.is-disabled[data-v-022e3781]{opacity:1}.upgrade-wrap[data-v-022e3781]{border:1px solid #ddd;margin-bottom:2rem;padding:1rem 0 1rem 0}.lan-item[data-v-022e3781]{margin-bottom:0}.el-switch.is-disabled[data-v-64b81c5b]{opacity:1}.green[data-v-64b81c5b]{font-weight:700}img.system[data-v-64b81c5b]{height:1.4rem;margin-right:.4rem;border:1px solid #eee}.el-switch.is-disabled[data-v-6941c158]{opacity:1}ul li[data-v-6941c158]{padding-left:2rem}a[data-v-2ee190a4]{text-decoration:underline}a+a[data-v-2ee190a4]{margin-left:1rem}a.green[data-v-2ee190a4]{font-weight:700}.head[data-v-6897ed85]{padding-bottom:1rem}.green[data-v-6897ed85]{color:green;font-weight:700}.error[data-v-6897ed85]{font-weight:700}.error .el-icon[data-v-6897ed85]{vertical-align:text-bottom}.head[data-v-7d65167d]{padding-bottom:1rem}.error[data-v-7d65167d]{font-weight:700}.error .el-icon[data-v-7d65167d]{vertical-align:text-bottom}.head[data-v-8c388c86]{padding-bottom:1rem}.blue[data-v-8c388c86]{color:#409eff}.dropdown[data-v-8c388c86]{border:1px solid #ddd;padding:.4rem;font-size:1.3rem;border-radius:.4rem;position:relative}.dropdown .el-icon[data-v-8c388c86]{vertical-align:middle}.dropdown .badge[data-v-8c388c86]{position:absolute;right:-1rem;top:-50%;border-radius:10px;background-color:#f1ae05;color:#fff;padding:.2rem .6rem;font-size:1.2rem}.table-sort.el-table th.el-table__cell.is-leaf{border-bottom:0}.table-sort.el-table .el-table__inner-wrapper:before{height:0}.home-list-wrap[data-v-4766ad40]{padding:1rem}.home-list-wrap .page[data-v-4766ad40]{padding-top:1rem}.home-list-wrap .page-wrap[data-v-4766ad40]{display:inline-block}

View File

@@ -1 +1 @@
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>linker.web</title><link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/><script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script><script defer="defer" src="js/chunk-vendors.3be25225.js"></script><script defer="defer" src="js/app.0e347be3.js"></script><link href="css/chunk-vendors.d8267b33.css" rel="stylesheet"><link href="css/app.7bd6c330.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but linker.web doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html> <!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>linker.web</title><link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/><script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script><script defer="defer" src="js/chunk-vendors.3be25225.js"></script><script defer="defer" src="js/app.3d2b2fb0.js"></script><link href="css/chunk-vendors.d8267b33.css" rel="stylesheet"><link href="css/app.7bd6c330.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but linker.web doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -98,7 +98,7 @@ namespace linker.tun
/// 检查网卡是否可用 /// 检查网卡是否可用
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public Task<bool> CheckAvailable(); public Task<bool> CheckAvailable(bool order = false);
} }
/// <summary> /// <summary>

View File

@@ -341,7 +341,7 @@ namespace linker.tun
return output; return output;
} }
public async Task<bool> CheckAvailable() public async Task<bool> CheckAvailable(bool order = false)
{ {
string output = CommandHelper.Linux(string.Empty, new string[] { $"ip link show {Name}" }); string output = CommandHelper.Linux(string.Empty, new string[] { $"ip link show {Name}" });
return await Task.FromResult(output.Contains("state UP")).ConfigureAwait(false); return await Task.FromResult(output.Contains("state UP")).ConfigureAwait(false);

View File

@@ -184,7 +184,7 @@ namespace linker.tun
} }
public async Task<bool> CheckAvailable() public async Task<bool> CheckAvailable(bool order = false)
{ {
return await Task.FromResult(true).ConfigureAwait(false); return await Task.FromResult(true).ConfigureAwait(false);
} }

View File

@@ -1,6 +1,5 @@
using linker.libs; using linker.libs;
using linker.libs.timer; using linker.libs.timer;
using System.Buffers.Binary;
using System.Net; using System.Net;
namespace linker.tun namespace linker.tun
@@ -285,9 +284,9 @@ namespace linker.tun
} }
public async Task<bool> CheckAvailable() public async Task<bool> CheckAvailable(bool order = false)
{ {
return await linkerTunDevice.CheckAvailable(); return await linkerTunDevice.CheckAvailable(order);
} }
} }
} }

View File

@@ -154,14 +154,17 @@ namespace linker.tun
if (session == 0) return; if (session == 0) return;
try try
{ {
WinTun.SetEvent(waitHandle); IntPtr oldSession = session;
WinTun.WintunEndSession(session); IntPtr oldWaitHandle = waitHandle;
CommandHelper.Windows(string.Empty, new string[] { $"netsh interface set interface {Name} enable" }); CommandHelper.Windows(string.Empty, new string[] { $"netsh interface set interface {Name} enable" });
session = WinTun.WintunStartSession(adapter, 0x400000); session = WinTun.WintunStartSession(adapter, 0x400000);
waitHandle = WinTun.WintunGetReadWaitEvent(session); waitHandle = WinTun.WintunGetReadWaitEvent(session);
AddIPV4(); AddIPV4();
AddIPV6(); AddIPV6();
WinTun.SetEvent(oldWaitHandle);
WinTun.WintunEndSession(oldSession);
} }
catch (Exception) catch (Exception)
{ {
@@ -391,11 +394,12 @@ namespace linker.tun
} }
} }
public async Task<bool> CheckAvailable() public async Task<bool> CheckAvailable(bool order = false)
{ {
NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces(); NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();
InterfaceOrder(interfaces); if (order)
InterfaceOrder(interfaces);
NetworkInterface networkInterface = interfaces.FirstOrDefault(c => c.Name == Name || c.Description == $"{Name} Tunnel" || c.Name.Contains(Name)); NetworkInterface networkInterface = interfaces.FirstOrDefault(c => c.Name == Name || c.Description == $"{Name} Tunnel" || c.Name.Contains(Name));
UnicastIPAddressInformation firstIpv4 = networkInterface?.GetIPProperties() UnicastIPAddressInformation firstIpv4 = networkInterface?.GetIPProperties()

View File

@@ -117,7 +117,6 @@ namespace linker.tunnel
{ {
if (tunnelMessengerAdapter.ServerHost == null) return; if (tunnelMessengerAdapter.ServerHost == null) return;
Console.WriteLine(tunnelMessengerAdapter.ServerHost);
GetLocalIP(tunnelMessengerAdapter.ServerHost).ContinueWith((result) => GetLocalIP(tunnelMessengerAdapter.ServerHost).ContinueWith((result) =>
{ {
if (tunnelMessengerAdapter.PortMapPrivate > 0) if (tunnelMessengerAdapter.PortMapPrivate > 0)

View File

@@ -154,6 +154,7 @@ namespace linker.tunnel.connection
/// </summary> /// </summary>
public LastTicksManager LastTicks { get; } public LastTicksManager LastTicks { get; }
/// <summary> /// <summary>
/// 发送数据 /// 发送数据
/// </summary> /// </summary>
@@ -175,6 +176,10 @@ namespace linker.tunnel.connection
/// <param name="userToken">自定义数据,回调带上</param> /// <param name="userToken">自定义数据,回调带上</param>
public void BeginReceive(ITunnelConnectionReceiveCallback callback, object userToken); public void BeginReceive(ITunnelConnectionReceiveCallback callback, object userToken);
public void StartPacketMerge()
{
}
public string ToString(); public string ToString();
public bool Equals(ITunnelConnection connection); public bool Equals(ITunnelConnection connection);
} }

View File

@@ -41,6 +41,7 @@ namespace linker.tunnel.connection
public LastTicksManager LastTicks { get; private set; } = new LastTicksManager(); public LastTicksManager LastTicks { get; private set; } = new LastTicksManager();
[JsonIgnore] [JsonIgnore]
public QuicStream Stream { get; init; } public QuicStream Stream { get; init; }
[JsonIgnore] [JsonIgnore]
@@ -55,12 +56,11 @@ namespace linker.tunnel.connection
private ITunnelConnectionReceiveCallback callback; private ITunnelConnectionReceiveCallback callback;
private CancellationTokenSource cancellationTokenSource; private CancellationTokenSource cancellationTokenSource;
private object userToken; private object userToken;
private ReceiveDataBuffer bufferCache = new ReceiveDataBuffer(); private readonly ReceiveDataBuffer bufferCache = new ReceiveDataBuffer();
private LastTicksManager pingTicks = new(); private readonly LastTicksManager pingTicks = new();
private byte[] pingBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.tcp.ping"); private readonly byte[] pingBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.tcp.ping");
private byte[] pongBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.tcp.pong"); private readonly byte[] pongBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.tcp.pong");
private bool pong = true;
/// <summary> /// <summary>
@@ -153,7 +153,6 @@ namespace linker.tunnel.connection
else if (packet.Span.SequenceEqual(pongBytes)) else if (packet.Span.SequenceEqual(pongBytes))
{ {
Delay = (int)pingTicks.Diff(); Delay = (int)pingTicks.Diff();
pong = true;
} }
} }
@@ -201,7 +200,6 @@ namespace linker.tunnel.connection
} }
catch (Exception) catch (Exception)
{ {
pong = true;
Dispose(); Dispose();
} }
finally finally

View File

@@ -6,6 +6,7 @@ using System.Net;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using System.Text; using System.Text;
using System.Net.Sockets; using System.Net.Sockets;
using System.IO.Pipelines;
namespace linker.tunnel.connection namespace linker.tunnel.connection
{ {
@@ -39,6 +40,7 @@ namespace linker.tunnel.connection
public LastTicksManager LastTicks { get; private set; } = new LastTicksManager(); public LastTicksManager LastTicks { get; private set; } = new LastTicksManager();
[JsonIgnore] [JsonIgnore]
public SslStream Stream { get; init; } public SslStream Stream { get; init; }
@@ -49,19 +51,17 @@ namespace linker.tunnel.connection
private ITunnelConnectionReceiveCallback callback; private ITunnelConnectionReceiveCallback callback;
private CancellationTokenSource cancellationTokenSource; private CancellationTokenSource cancellationTokenSource;
private object userToken; private object userToken;
private ReceiveDataBuffer bufferCache = new ReceiveDataBuffer(); private readonly ReceiveDataBuffer bufferCache = new ReceiveDataBuffer();
private LastTicksManager pingTicks = new LastTicksManager(); private readonly LastTicksManager pingTicks = new LastTicksManager();
private byte[] pingBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.tcp.ping"); private readonly byte[] pingBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.tcp.ping");
private byte[] pongBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.tcp.pong"); private readonly byte[] pongBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.tcp.pong");
private bool pong = true;
/// <summary> /// <summary>
/// 开始接收数据 /// 开始接收数据
/// </summary> /// </summary>
/// <param name="callback">数据回调</param> /// <param name="callback">数据回调</param>
/// <param name="userToken">自定义数据</param> /// <param name="userToken">自定义数据</param>
/// <param name="byFrame">是否处理粘包true时请在首部4字节标注数据长度</param>
public void BeginReceive(ITunnelConnectionReceiveCallback callback, object userToken) public void BeginReceive(ITunnelConnectionReceiveCallback callback, object userToken)
{ {
if (this.callback != null) return; if (this.callback != null) return;
@@ -163,7 +163,6 @@ namespace linker.tunnel.connection
else if (packet.Span.SequenceEqual(pongBytes)) else if (packet.Span.SequenceEqual(pongBytes))
{ {
Delay = (int)pingTicks.Diff(); Delay = (int)pingTicks.Diff();
pong = true;
return; return;
} }
} }
@@ -226,7 +225,6 @@ namespace linker.tunnel.connection
} }
catch (Exception) catch (Exception)
{ {
pong = true;
Dispose(); Dispose();
} }
finally finally
@@ -236,12 +234,21 @@ namespace linker.tunnel.connection
ArrayPool<byte>.Shared.Return(heartData); ArrayPool<byte>.Shared.Return(heartData);
} }
private SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1);
private readonly SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1);
public async Task<bool> SendAsync(ReadOnlyMemory<byte> data) public async Task<bool> SendAsync(ReadOnlyMemory<byte> data)
{ {
if (callback == null) return false; if (callback == null) return false;
if (pipe != null)
{
Memory<byte> memory = pipe.Writer.GetMemory(data.Length);
data.CopyTo(memory);
pipe.Writer.Advance(data.Length);
await pipe.Writer.FlushAsync();
return true;
}
if (Stream != null) if (Stream != null)
{ {
await semaphoreSlim.WaitAsync().ConfigureAwait(false); await semaphoreSlim.WaitAsync().ConfigureAwait(false);
@@ -278,6 +285,16 @@ namespace linker.tunnel.connection
{ {
if (callback == null) return false; if (callback == null) return false;
if (pipe != null)
{
ReadOnlyMemory<byte> data = buffer.AsMemory(offset, length);
Memory<byte> memory = pipe.Writer.GetMemory(data.Length);
data.CopyTo(memory);
pipe.Writer.Advance(data.Length);
await pipe.Writer.FlushAsync();
return true;
}
if (Stream != null) if (Stream != null)
{ {
await semaphoreSlim.WaitAsync().ConfigureAwait(false); await semaphoreSlim.WaitAsync().ConfigureAwait(false);
@@ -311,11 +328,11 @@ namespace linker.tunnel.connection
return false; return false;
} }
/*
private Pipe pipe; private Pipe pipe;
public void PipeLines() public void StartPacketMerge()
{ {
pipe = new Pipe(new PipeOptions { }); pipe = new Pipe(new PipeOptions(pauseWriterThreshold:800*1024));
_ = Reader(); _ = Reader();
} }
private async Task Reader() private async Task Reader()
@@ -328,13 +345,13 @@ namespace linker.tunnel.connection
{ {
break; break;
} }
ReadOnlySequence<byte> buffer = result.Buffer; ReadOnlySequence<byte> buffer = result.Buffer;
while (buffer.Length > 0) while (buffer.Length > 0)
{ {
int chunkSize = (int)Math.Min(buffer.Length, 8192); int chunkSize = (int)Math.Min(buffer.Length, 8192);
ReadOnlySequence<byte> chunk = buffer.Slice(0, chunkSize); ReadOnlySequence<byte> chunk = buffer.Slice(0, chunkSize);
if (Stream != null) await semaphoreSlim.WaitAsync().ConfigureAwait(false); if (Stream != null) await semaphoreSlim.WaitAsync().ConfigureAwait(false);
try try
{ {
@@ -367,27 +384,8 @@ namespace linker.tunnel.connection
} }
pipe.Reader.AdvanceTo(result.Buffer.End); pipe.Reader.AdvanceTo(result.Buffer.End);
} }
} }
public async Task<bool> WriteAsync(ReadOnlyMemory<byte> data)
{
Memory<byte> memory = pipe.Writer.GetMemory(data.Length);
data.CopyTo(memory);
pipe.Writer.Advance(data.Length);
await pipe.Writer.FlushAsync();
return true;
}
public async Task<bool> WriteAsync(byte[] buffer, int offset, int length)
{
ReadOnlyMemory<byte> data = buffer.AsMemory(offset, length);
Memory<byte> memory = pipe.Writer.GetMemory(data.Length);
data.CopyTo(memory);
pipe.Writer.Advance(data.Length);
await pipe.Writer.FlushAsync();
return true;
}
*/
public void Dispose() public void Dispose()
{ {
@@ -407,6 +405,14 @@ namespace linker.tunnel.connection
Socket?.SafeClose(); Socket?.SafeClose();
try
{
pipe?.Writer.Complete();
pipe?.Reader.Complete();
}
catch (Exception)
{ }
} }
public override string ToString() public override string ToString()
{ {

View File

@@ -5,7 +5,6 @@ using System.Net;
using System.Text; using System.Text;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using System.Net.Sockets; using System.Net.Sockets;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace linker.tunnel.connection namespace linker.tunnel.connection
{ {
@@ -62,12 +61,11 @@ namespace linker.tunnel.connection
private CancellationTokenSource cancellationTokenSource; private CancellationTokenSource cancellationTokenSource;
private object userToken; private object userToken;
private LastTicksManager pingTicks = new LastTicksManager(); private readonly LastTicksManager pingTicks = new LastTicksManager();
private byte[] pingBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.udp.ping"); private readonly byte[] pingBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.udp.ping");
private byte[] pongBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.udp.pong"); private readonly byte[] pongBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.udp.pong");
private byte[] finBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.udp.fing"); private readonly byte[] finBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.udp.fing");
private byte[] ttlBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.ttl"); private readonly byte[] ttlBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.ttl");
private bool pong = true;
/// <summary> /// <summary>
@@ -148,7 +146,6 @@ namespace linker.tunnel.connection
else if (memory.Span.SequenceEqual(pongBytes)) else if (memory.Span.SequenceEqual(pongBytes))
{ {
Delay = (int)pingTicks.Diff(); Delay = (int)pingTicks.Diff();
pong = true;
} }
else if (memory.Span.SequenceEqual(finBytes)) else if (memory.Span.SequenceEqual(finBytes))
{ {
@@ -226,7 +223,6 @@ namespace linker.tunnel.connection
} }
catch (Exception) catch (Exception)
{ {
pong = true;
Dispose(); Dispose();
} }
finally finally
@@ -236,7 +232,6 @@ namespace linker.tunnel.connection
ArrayPool<byte>.Shared.Return(heartData); ArrayPool<byte>.Shared.Return(heartData);
} }
private byte[] encodeBuffer = new byte[8 * 1024]; private byte[] encodeBuffer = new byte[8 * 1024];
public async Task<bool> SendAsync(ReadOnlyMemory<byte> data) public async Task<bool> SendAsync(ReadOnlyMemory<byte> data)
{ {
@@ -308,6 +303,7 @@ namespace linker.tunnel.connection
return false; return false;
} }
public void Dispose() public void Dispose()
{ {
@@ -337,4 +333,4 @@ namespace linker.tunnel.connection
return connection != null && GetHashCode() == connection.GetHashCode() && IPEndPoint.Equals(connection.IPEndPoint); return connection != null && GetHashCode() == connection.GetHashCode() && IPEndPoint.Equals(connection.IPEndPoint);
} }
} }
} }

View File

@@ -38,6 +38,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Mono.Nat" Version="3.0.4" /> <PackageReference Include="Mono.Nat" Version="3.0.4" />
<PackageReference Include="System.IO.Pipelines" Version="9.0.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -6,15 +6,19 @@
<el-form-item label="网卡名" prop="Name"> <el-form-item label="网卡名" prop="Name">
<el-input v-model="state.ruleForm.Name" style="width:14rem" /> <span>留空则使用本组网络的设置</span> <el-input v-model="state.ruleForm.Name" style="width:14rem" /> <span>留空则使用本组网络的设置</span>
</el-form-item> </el-form-item>
<el-form-item label="网卡IP" prop="IP"> <el-form-item label="网卡IP" prop="IP" class="mgb-0">
<el-input v-model="state.ruleForm.IP" style="width:14rem" /> <el-input v-model="state.ruleForm.IP" style="width:14rem" />
<span>/</span> <span>/</span>
<el-input @change="handlePrefixLengthChange" v-model="state.ruleForm.PrefixLength" style="width:4rem" /> <el-input @change="handlePrefixLengthChange" v-model="state.ruleForm.PrefixLength" style="width:4rem" />
<span style="width: 2rem;"></span>
<el-checkbox v-model="state.ruleForm.ShowDelay" label="显示延迟" size="large" style="margin-right:1rem" /> </el-form-item>
<el-checkbox v-model="state.ruleForm.AutoConnect" label="自动连接" size="large" style="margin-right:1rem" /> <el-form-item label="">
<el-checkbox v-model="state.ruleForm.Multicast" label="禁用广播" size="large" /> <el-checkbox class="mgr-1" v-model="state.ruleForm.ShowDelay" label="显示延迟" size="large" />
<el-checkbox v-model="state.ruleForm.Nat" label="禁用NAT" size="large" /> <el-checkbox class="mgr-1" v-model="state.ruleForm.AutoConnect" label="自动连接" size="large" />
<el-checkbox class="mgr-1" v-model="state.ruleForm.Multicast" label="禁用广播" size="large" />
<el-checkbox class="mgr-1" v-model="state.ruleForm.Nat" label="禁用NAT" size="large" />
<el-checkbox class="mgr-1" v-model="state.ruleForm.TcpMerge" label="TCP包合并" size="large" />
<el-checkbox v-model="state.ruleForm.InterfaceOrder" label="调整网卡顺序" size="large" />
</el-form-item> </el-form-item>
<el-form-item prop="upgrade" class="mgb-0"> <el-form-item prop="upgrade" class="mgb-0">
<el-checkbox v-model="state.ruleForm.Upgrade" label="我很懂,我要使用高级功能(点对网和网对网)" size="large" /> <el-checkbox v-model="state.ruleForm.Upgrade" label="我很懂,我要使用高级功能(点对网和网对网)" size="large" />
@@ -68,6 +72,8 @@ export default {
Upgrade: tuntap.value.current.Upgrade, Upgrade: tuntap.value.current.Upgrade,
Multicast: tuntap.value.current.Multicast, Multicast: tuntap.value.current.Multicast,
Nat: tuntap.value.current.Nat, Nat: tuntap.value.current.Nat,
TcpMerge: tuntap.value.current.TcpMerge,
InterfaceOrder: tuntap.value.current.InterfaceOrder,
Forwards: tuntap.value.current.Forwards, Forwards: tuntap.value.current.Forwards,
Name: tuntap.value.current.Name, Name: tuntap.value.current.Name,
}, },
@@ -112,6 +118,8 @@ export default {
json.Upgrade = state.ruleForm.Upgrade; json.Upgrade = state.ruleForm.Upgrade;
json.Multicast = state.ruleForm.Multicast; json.Multicast = state.ruleForm.Multicast;
json.Nat = state.ruleForm.Nat; json.Nat = state.ruleForm.Nat;
json.TcpMerge = state.ruleForm.TcpMerge;
json.InterfaceOrder = state.ruleForm.InterfaceOrder;
json.Forwards = forwardDom.value ? forwardDom.value.getData() : tuntap.value.current.Forwards; json.Forwards = forwardDom.value ? forwardDom.value.getData() : tuntap.value.current.Forwards;
json.Name = state.ruleForm.Name; json.Name = state.ruleForm.Name;
updateTuntap(json).then(() => { updateTuntap(json).then(() => {

View File

@@ -21,8 +21,10 @@
<Authors>snltty</Authors> <Authors>snltty</Authors>
<Company>snltty</Company> <Company>snltty</Company>
<Description>1. 优化数据同步 <Description>1. 优化数据同步
2. 优化linux网卡,我感觉网卡速度比较正常了 2. 优化linux的tun网卡网卡读写分离提高性能
3. 建议更新</Description> 3. 优化windows网卡的禁用自动启用
4. 增加TCP包合并。网卡IP包多个合并一起发送
5. 建议更新</Description>
<Copyright>snltty</Copyright> <Copyright>snltty</Copyright>
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl> <PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl> <RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>

View File

@@ -1,5 +1,7 @@
v1.7.1 v1.7.1
2025-03-23 20:24:26 2025-03-26 00:16:31
1. 优化数据同步 1. 优化数据同步
2. 优化linux网卡,我感觉网卡速度比较正常了 2. 优化linux的tun网卡网卡读写分离提高性能
3. 建议更新 3. 优化windows网卡的禁用自动启用
4. 增加TCP包合并。网卡IP包多个合并一起发送
5. 建议更新