.net core 多任务 端口转发程序 Console版

发布时间 2023-09-07 17:36:05作者: 土豆赛叩

Program.cs

using System.Net;

namespace PortProxy
{
    public class Program
    {
        private static List<ProxyClient> clients = new List<ProxyClient>();

        public static void Main(string[] args)
        {
            var lines = File.ReadAllLines("conf.txt")
                 .Select(e => e.Trim())
                 .Where(e => e.Length > 0 && !e.StartsWith("#"));

            foreach (var line in lines)
            {
                var sp = line.Split(' ');
                var local = IPEndPoint.Parse(sp[0]);
                var remote = IPEndPoint.Parse(sp[1]);
                var client = new ProxyClient(local, remote);
                client.Start();
                clients.Add(client);
            }


            while (true)
            {
                Console.Clear();
                Console.Write("{0, -22}", "LOCAL ENDPOINT");
                Console.Write("{0, -22}", "REMOTE ENDPOINT");
                Console.Write("{0, -10}", "CLIENTS");

                Console.Write("{0, -12}", "UP/s");
                Console.Write("{0, -12}", "DOWN/s");

                Console.Write("{0, -12}", "UP TOTAL");
                Console.Write("{0, -12}", "DOWN TOTAL");
                Console.WriteLine("STATUS");

                foreach (var client in clients)
                {
                    Console.Write("{0, -22}", client.LocalEndPoint);
                    Console.Write("{0, -22}", client.RemoteEndPoint);
                    Console.Write("{0, -10}", client.ClientNum);
                    Console.Write("{0, -12}", client.UpFlowSecond);
                    Console.Write("{0, -12}", client.DownFlowSecond);
                    Console.Write("{0, -12}", client.UpFlowTotal);
                    Console.Write("{0, -12}", client.DownFlowTotal);
                    Console.WriteLine(client.Status);
                    client.ResetFlow();
                }
                Thread.Sleep(1000);
            }
        }
    }
}

ProxyClient.cs

using System.Buffers;
using System.Net.Sockets;
using System.Net;
namespace PortProxy
{

    internal class SizeNumber
    {

        public SizeNumber(long value)
        {
            _value = value;
        }


        private long _value = 0;
        private string[] NUMBER_FORMAT_LEVELS = new string[] { "B", "KB", "MB", "GB", "TB", "PB" };



        public void Reset()
        {
            _value = 0;
        }


        public void Add(long value)
        {
            //Interlocked.Add
            _value += value;
        }



        public override string ToString()
        {
            int counter = 0;
            double number = _value;
            int maxCount = NUMBER_FORMAT_LEVELS.Length - 1;
            while (Math.Round(number / 1024) >= 1)
            {
                number = number / 1024;
                counter++;
                if (counter >= maxCount)
                {
                    break;
                }
            }
            return $"{string.Format("{0:0.00}", number)}{NUMBER_FORMAT_LEVELS[counter]}";
        }

        public string Format(long bytes, string formatString = "{0:0.00}")
        {
            int counter = 0;
            double number = bytes;
            int maxCount = NUMBER_FORMAT_LEVELS.Length - 1;
            while (Math.Round(number / 1024) >= 1)
            {
                number = number / 1024;
                counter++;
                if (counter >= maxCount)
                {
                    break;
                }
            }
            return $"{string.Format(formatString, number)}{NUMBER_FORMAT_LEVELS[counter]}";
        }
    }










    internal class ProxyClient
    {
        private CancellationTokenSource cancelSource { get; set; }
        private TcpListener listener { get; set; }
        public IPEndPoint LocalEndPoint { get; set; }
        public IPEndPoint RemoteEndPoint { get; set; }
        public Int32 BufferSize { get; set; } = 81920;

        public Int32 ClientNum = 0;

        public String Status = "";

        public SizeNumber UpFlowTotal = new SizeNumber(0);
        public SizeNumber DownFlowTotal = new SizeNumber(0);

        public SizeNumber UpFlowSecond = new SizeNumber(0);
        public SizeNumber DownFlowSecond = new SizeNumber(0);


        public ProxyClient(IPEndPoint localE, IPEndPoint remoteE)
        {
            cancelSource = new CancellationTokenSource();
            this.LocalEndPoint = localE;
            this.RemoteEndPoint = remoteE;
        }

        public void ResetFlow()
        {
            UpFlowSecond.Reset();
            DownFlowSecond.Reset();
        }


        public void Stop()
        {
            cancelSource.Cancel();
            this.Status = "Stop";
        }



        public void Start()
        {
            try
            {
                cancelSource.TryReset();
                listener = new TcpListener(LocalEndPoint);
                listener.Start();
                Task.Run(AcceptClients, cancelSource.Token);
                this.Status = "Runing";
            }
            catch (Exception ex)
            {
                this.Status = "Error " + ex.Message;
            }
        }


        private async Task AcceptClients()
        {
            while (!cancelSource.IsCancellationRequested)
            {
                TcpClient client = await listener.AcceptTcpClientAsync(cancelSource.Token);
                var task = Task.Run(() => HandleConnectionAsync(client), cancelSource.Token);
            }
        }





        private async Task HandleConnectionAsync(TcpClient client)
        {
            var remote = new TcpClient();
            try
            {
                Interlocked.Increment(ref ClientNum);
                await remote.ConnectAsync(RemoteEndPoint);

                NetworkStream clientStream = client.GetStream();
                NetworkStream forwardStream = remote.GetStream();
                Task copyToForward = CopyToAsync(clientStream, forwardStream, (f) =>
                {
                    UpFlowTotal.Add(f);
                    UpFlowSecond.Add(f);
                });
                Task copyToClient = CopyToAsync(forwardStream, clientStream, (f) =>
                {
                    DownFlowTotal.Add(f);
                    DownFlowSecond.Add(f);
                });
                await Task.WhenAny(copyToForward, copyToClient);
                remote.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error: {0}", ex.Message);
            }
            finally
            {
                client.Close();
                Interlocked.Decrement(ref ClientNum);
            }
        }


        private async Task CopyToAsync(Stream source, Stream destination, Action<int> flowInc)
        {
            byte[] buffer = ArrayPool<byte>.Shared.Rent(BufferSize);
            try
            {
                int bytesRead;
                while ((bytesRead = await source.ReadAsync(new Memory<byte>(buffer), cancelSource.Token).ConfigureAwait(false)) != 0)
                {
                    flowInc(bytesRead);
                    await destination.WriteAsync(new ReadOnlyMemory<byte>(buffer, 0, bytesRead), cancelSource.Token).ConfigureAwait(false);
                }
            }
            finally
            {
                ArrayPool<byte>.Shared.Return(buffer);
            }
        }

    }
}

conf.txt




0.0.0.0:11000 192.168.1.105:8800

0.0.0.0:10000 192.168.1.109:8085