Упрощенный аналог ngrok - Трех или четырехзвенная архитектура? - C#

Узнай цену своей работы

Формулировка задачи:

тааак... короче, есть задумка создать упрощенный аналог ngrok. Для своих нужд) есть комп №1, есть комп №2, есть внешний сервер со статическим IP. Комп 1 и 2 находятся в разных сегментах сети, которые оба имеют доступ в инет, например, через роутер. на компе №1 запускаю приложение, которое коннектится к серваку на заранее известный порт, на компе №2 запускается приложение, которое так же коннектится к серваку, но на неопределенный порт (использую стороннюю библиотеку). На серваке крутится третье приложение, которое перекидывает данные из одного сокета в другой, но вот незадача - при передаче потока http данных от компа №1 до приложения на компе №2 (скажем, mjpg поток) после передачи одного фрейма приложение на компе №1 перестает генерить и передавать этот поток. Код:
static void ConnectAndProcess()
        {
            
            try
            {
                _client.Connect(IPAddress.Parse(externIp), port);
            }
            catch (Exception)
            {
                _client = new TcpClient(AddressFamily.InterNetwork);
            }
            
            if (_client.Connected)
            {
                Console.WriteLine("Подключился");
                using (var ns = _client.GetStream())
                {
// так сервер определит, какой сокет является источником данных
                    var txtToSend = Encoding.ASCII.GetBytes("client"); 
                    ns.Write(txtToSend, 0, txtToSend.Length);
                    try
                    {
                        int count;
                        var buffer = new byte[1024 * 512];
                        while ((count = ns.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            var str = Encoding.ASCII.GetString(buffer, 0, count);
                            Console.WriteLine("Принято от сервера {0} байт:\n{1}", count, str);
                            if (str.Contains("start"))
                            {
                                Console.WriteLine("Начинаю вещать видеопоток");
                                using (var writer = new MjpegWriter(ns))
                                {
                                    _videoStreaming = true;
                                    writer.WriteHeader();
                                    foreach (var imgStream in  ScreenWork.Snapshots(true).Streams())
                                    {
                                        Thread.Sleep(50);
                                        writer.Write(imgStream);
                                        Console.WriteLine("Sended " + imgStream.ToArray().Length);
                                    }
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Trace.WriteLine(string.Format("{0} Ошибка сокета. Exception {1}", DateTime.Now, ex.Message));
                    }
                }
            }
            else Trace.WriteLine(string.Format("{0} Не удалось подключиться", DateTime.Now));
            Trace.WriteLine(string.Format("{0} Подключение окончено, требуется переподключение", DateTime.Now));
        }
Код класса ScreenWork
public static class ScreenWork
    {
        public static IEnumerable<Image> Snapshots()
        {
            return Snapshots(true);
        }
 
        public static Size ImgSize { get; set; }
 
        /// <summary>
        /// Returns a 
        /// </summary>
        /// <param name="showCursor"></param>
        /// <returns></returns>
        public static IEnumerable<Image> Snapshots(bool showCursor)
        {
            if (ImgSize.Width == 0 || ImgSize.Height == 0)
            {
                ImgSize = new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
            }
            Size size = new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
 
            Bitmap srcImage = new Bitmap(size.Width, size.Height);
            Graphics srcGraphics = Graphics.FromImage(srcImage);
 
            bool scaled = (ImgSize.Width != size.Width || ImgSize.Height != size.Height);
 
            Bitmap dstImage = srcImage;
            Graphics dstGraphics = srcGraphics;
 
            if (scaled)
            {
                dstImage = new Bitmap(ImgSize.Width, ImgSize.Height);
                dstGraphics = Graphics.FromImage(dstImage);
            }
 
            var src = new Rectangle(0, 0, size.Width, size.Height);
            var dst = new Rectangle(0, 0, ImgSize.Width, ImgSize.Height);
            var curSize = new Size(32, 32);
 
            while (true)
            {
                srcGraphics.CopyFromScreen(0, 0, 0, 0, size);
 
                if (showCursor)
                    Cursors.Default.Draw(srcGraphics, new Rectangle(Cursor.Position, curSize));
 
                if (scaled)
                    dstGraphics.DrawImage(srcImage, dst, src, GraphicsUnit.Pixel);
 
                yield return dstImage;
 
            }
 
            srcGraphics.Dispose();
            dstGraphics.Dispose();
 
            srcImage.Dispose();
            dstImage.Dispose();
 
            yield break;
        }
 
        public static IEnumerable<MemoryStream> Streams(this IEnumerable<Image> source)
        {
            var ms = new MemoryStream();
            foreach (var img in source)
            {
                ms.SetLength(0);
                img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                yield return ms;
            }
            ms.Close();
            ms = null;
            yield break;
        }
    }
Код класса MjpegWriter
public class MjpegWriter:IDisposable 
    {
 
        private static byte[] _crlf = new byte[] { 13, 10 };
        private static byte[] _emptyLine = new byte[] { 13, 10, 13, 10};
 
        private string _boundary;
 
        public MjpegWriter(Stream stream)
            : this(stream, "--boundary")
        {
 
        }
 
        public MjpegWriter(Stream stream,string boundary)
        {
 
            this.Stream = stream;
            this.Boundary = boundary;
        }
 
        public string Boundary { get; private set; }
        public Stream Stream { get; private set; }
 
        public void WriteHeader()
        {
 
            Write( 
                    "HTTP/1.1 200 OK\r\n" +
                    "Content-Type: multipart/x-mixed-replace; boundary=" +
                    this.Boundary +
                    "\r\n"
                 );
 
            this.Stream.Flush();
       }
 
        public void Write(Image image)
        {
            MemoryStream ms = BytesOf(image);
            this.Write(ms);
        }
 
        public void Write(MemoryStream imageStream)
        {
 
            StringBuilder sb = new StringBuilder();
 
            sb.AppendLine();
            sb.AppendLine(this.Boundary);
            sb.AppendLine("Content-Type: image/jpeg");
            sb.AppendLine("Content-Length: " + imageStream.Length.ToString());
            sb.AppendLine(); 
 
            Write(sb.ToString());
            imageStream.WriteTo(this.Stream);
            Write("\r\n");
            
            this.Stream.Flush();
 
        }
 
        private void Write(byte[] data)
        {
            this.Stream.Write(data, 0, data.Length);
        }
 
        private void Write(string text)
        {
            byte[] data = BytesOf(text);
            this.Stream.Write(data, 0, data.Length);
        }
 
        private static byte[] BytesOf(string text)
        {
            return Encoding.ASCII.GetBytes(text);
        }
 
        private static MemoryStream BytesOf(Image image)
        {
            MemoryStream ms = new MemoryStream();
            image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
            return ms;
        }
 
        public string ReadRequest(int length)
        {
 
            byte[] data = new byte[length];
            int count = this.Stream.Read(data,0,data.Length);
 
            if (count != 0)
                return Encoding.ASCII.GetString(data, 0, count);
 
            return null;
        }
 
        #region IDisposable Members
 
        public void Dispose()
        {
 
            try
            {
 
                if (this.Stream != null)
                    this.Stream.Dispose();
 
            }
            finally
            {
                this.Stream = null;
            }
        }
 
        #endregion
    }

Решение задачи: «Упрощенный аналог ngrok - Трех или четырехзвенная архитектура?»

textual
Листинг программы
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
 
namespace MainServer
{
    class Program
    {
        static System.Net.IPEndPoint _point1, _point2;
        static  tcpServer.TcpServer tcpServer;
        static void Main(string[] args)
        {
            tcpServer = new tcpServer.TcpServer();
            tcpServer.Port = 5000;
            tcpServer.OnDataAvailable += tcpServer_OnDataAvailable;
            tcpServer.Open();
            while (true) {
                System.Threading.Thread.Sleep(10);
            }
        }
        static int indexPoint1, indexPoint2;
        static int countChangesPoint2;
 
        static void tcpServer_OnDataAvailable(tcpServer.TcpServerConnection connection)
        {
            var remoteIp = (IPEndPoint)connection.Socket.Client.RemoteEndPoint;
            byte[] byteData = readStream(connection.Socket);
            if (byteData != null)
            {
                if (byteData.Length == 6 && Encoding.ASCII.GetString(byteData) == "client")
                {
                    _point1= remoteIp;
                    int i = 0;
                    foreach (var conn in tcpServer.Connections)
                        if (EqEndPoints((IPEndPoint)conn.Socket.Client.RemoteEndPoint, _point1))
                        {
                            conn.Socket.ReceiveBufferSize = 1024 * 512;
                            indexPoint1= i;
                            break;
                        }
                        else i++;
                    return;
                }
 
                if (_point2== null && byteData.Length == 7 && Encoding.ASCII.GetString(byteData) == "point12")
                {
                    _point2 = remoteIp;
                    int i = 0;
                    foreach (var conn in tcpServer.Connections)
                        if (EqEndPoints((IPEndPoint)conn.Socket.Client.RemoteEndPoint, _point2))
                        {
                            indexPoint2 = i;
                            break;
                        }
                        else i++;
                    return;
                }
 
                if (countChangesPoint2 < 2 && _point2!= null && !EqEndPoints(remoteIp, _point2))
                {
                    countChangesPoint2++;
                    _point2= remoteIp;
                    int i = 0;
                    foreach (var conn in tcpServer.Connections)
                        if (EqEndPoints((IPEndPoint)conn.Socket.Client.RemoteEndPoint, _point2))
                        {
                            indexPoint2 = i;
                            break;
                        }
                        else i++;
                }
                
                if (_client != null && _watcher != null)
                {
                    if (EqEndPoints(remoteIp, _point1))
                    {
                        tcpServer.Connections[indexPoint2].sendData(Encoding.ASCII.GetString(byteData));
                    }
                    if (EqEndPoints(remoteIp, _point2))
                    {
                        tcpServer.Connections[indexPoint1].sendData(Encoding.ASCII.GetString(byteData));
                    }
                }
            }
        }
        protected static byte[] readStream(TcpClient client)
        {
            NetworkStream stream = client.GetStream();
            List<byte> lst = new List<byte>();
            while (stream.DataAvailable)
            {
                byte[] byteArr = new byte[1024 * 512];
                int s = stream.Read(byteArr, 0, 1024 * 512);
                Array.Resize(ref byteArr, s);
                lst.AddRange(byteArr);
                
                //call stream.Read(), read until end of packet/stream/other termination indicator
                //return data read as byte array
            }
            return lst.ToArray();
        }  
 
        static bool EqEndPoints(System.Net.IPEndPoint p1, System.Net.IPEndPoint p2)
        {
            if (p1 == null && p2 == null) return true;
            if (p1 != null && p2 != null)
                return p1.Address.ToString() == p2.Address.ToString() && p1.Port == p2.Port;
            return false;
        }
      
    }
}

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

12   голосов , оценка 4.083 из 5
Похожие ответы