sjsteve33171 Ответов: 1

Проблема с отправкой пакетов C#


Обзор заключается в том, что это проект для удаленной поддержки, такой как Teamviewer. У меня есть приложение брокера, клиента и техника.

В настоящее время клиентское приложение делает скриншот и отправляет его брокеру. Брокер понимает, что это скриншот, и отправляет его соответствующему техническому клиенту, который прошел предварительную аутентификацию.

Затем технический клиент получает изображение от брокера и отображает его в picturebox на конце технического клиента.

Проблема в том, что когда скриншот отправляется и отображается один раз, клиент выходит из строя, но я не получаю никаких исключений, поэтому я теряюсь и ищу помощи. Я ожидаю, что это что-то глупое / простое, но я не вижу, что именно.

Пример изображения - вы увидите, что клиент подключен к брокеру в приложении Technician, но в приложении broker он разбился и исчез.

[^]

Ниже приведен соответствующий код:

Клиент:
Примечание: Я также получаю количество экранов и текущее разрешение экрана и отправляю вместе со скриншотом для использования в конце техникума.
private int      ScreenToView            =   0;
private bool     SendMyScreen            =   false; //Set to true upon technician connection
private bool     ShowCursor              =   false;
public void SendScreen( )
        {
            //Holds the number of screens on the client machine
            int NumOfScreens = 0;

            while( SendMyScreen )
            {
                try
                {
                    //Get SS based on screen the technician are viewing
                    Bitmap bmpScreenshot = new Bitmap( Screen.AllScreens[ ScreenToView ].Bounds.Width, Screen.AllScreens[ ScreenToView ].Bounds.Height, PixelFormat.Format16bppRgb555 );
                    using Graphics gfxScreenshot = Graphics.FromImage( bmpScreenshot );
                    gfxScreenshot.CopyFromScreen( Screen.AllScreens[ ScreenToView ].Bounds.X, Screen.AllScreens[ ScreenToView ].Bounds.Y, 0, 0, Screen.AllScreens[ ScreenToView ].Bounds.Size, CopyPixelOperation.SourceCopy );
                        
                    if( ShowCursor )
                    {
                        CURSORINFO pci;
                        pci.cbSize = Marshal.SizeOf( typeof( CURSORINFO ) );

                        if( GetCursorInfo( out pci ) )
                        {
                            DrawIcon( gfxScreenshot.GetHdc( ), pci.ptScreenPos.x, pci.ptScreenPos.y, pci.hCursor );
                            gfxScreenshot.ReleaseHdc( );
                        }
                    }

                    //Save the screenshot into memory
                    using MemoryStream ms   =   new MemoryStream( );
                    bmpScreenshot.Save( ms, ImageFormat.Jpeg );

                    //Create our buffer based on memory length
                    byte[ ] ssBuffer = new byte[ ms.Length + 11 ];

                    //Set the command to screenshot
                    ssBuffer[ 0 ] = 2;

                    //Number of screens
                    foreach( Screen screen in Screen.AllScreens ) { NumOfScreens++; }
                    Array.Copy( BitConverter.GetBytes( NumOfScreens ), 0, ssBuffer, 1, 1 );

                    //Screen width & height
                    Array.Copy( BitConverter.GetBytes( Screen.AllScreens[ ScreenToView ].Bounds.Width ), 0, ssBuffer, 2, 4 );
                    Array.Copy( BitConverter.GetBytes( Screen.AllScreens[ ScreenToView ].Bounds.Height ), 0, ssBuffer, 6, 4 );

                    //Copy the screenshot into buffer at index 10 as 0-9 are info
                    Array.Copy( ms.ToArray( ), 0, ssBuffer, 10, ms.Length );

                    //Send Screen info to Broker
                    BrokerSocket.Send( ssBuffer, Convert.ToInt32( ms.Length + 10 ), SocketFlags.None );

                    //Reset screen number
                    NumOfScreens = 0;

                    //Wait before sending next
                    Thread.Sleep( 100 );
                }
                catch( Exception e )
                {
                    DebugLog( "SendScreen Exception: " + e.Message.ToString( ) );
                }
            }
        }


Посредник:
public void SendDataToTechnician( Socket clientSocket, byte[ ] data, int bytesRead )
        {
            try
            {
                if( Success.technicianSocket != null && Success.technicianSocket.Connected )
                {
                    Success.technicianSocket.Send( data );
                }
            }
            catch( Exception ex ) { DebugLog( "SendDataToTechnician Exception: " + ex.Message.ToString( ) ); }
        }


Техник:
public void ShowClientScreen( byte[ ] data, int dataRead )
        {
            try
            {
                //Create a new byte array
                byte[ ] imgData         =   new byte[ dataRead ];

                //Get Number Of Remote Screens
                byte[ ] NumOfScreens    =   new byte[ 4 ]; Array.Copy( data, 1, NumOfScreens, 0, 1 );
                Remote_Num_Of_Screens   =   BitConverter.ToInt32( NumOfScreens, 0 );

                //Get Remote Screen Resolution from array
                byte[ ] ScreenW         =   new byte[ 4 ]; Array.Copy( data, 2, ScreenW, 0, 4 );
                byte[ ] ScreenH         =   new byte[ 4 ]; Array.Copy( data, 6, ScreenH, 0, 4 );
                Remote_Screen_Width     =   BitConverter.ToInt32( ScreenW, 0 );
                Remote_Screen_Height    =   BitConverter.ToInt32( ScreenH, 0 );
             
                //Copy the largeBuffer into our temporary byte array from array 1 as 0 contains the command
                //Subtract 9 as we received 10 in information
                Array.Copy( data, 10, imgData, 0, dataRead -9 );

                //Using memorystream - Same method of how it was sent
                using MemoryStream ms = new MemoryStream( imgData );

                //Set Image
                Image RecvImage = Image.FromStream( ms );

                //Sets the image to be stretched into the picture window no mater it's size
                if( ScreenSize == PictureBoxSizeMode.StretchImage )
                {
                    MethodInvoker ChangeScreenImageTypeStretch = delegate
                    {
                        pictureBox1.SizeMode    =   PictureBoxSizeMode.StretchImage;
                        pictureBox1.Image       =   RecvImage;
                    };
                    Invoke( ChangeScreenImageTypeStretch );
                }
                else if( ScreenSize == PictureBoxSizeMode.Normal )
                {
                    MethodInvoker ChangeScreenImageTypeAutoSize = delegate
                    {
                        pictureBox1.SizeMode    =   PictureBoxSizeMode.Normal;
                        pictureBox1.Image       =   RecvImage;
                    };
                    Invoke( ChangeScreenImageTypeAutoSize );
                }
            
                //Invoke btnScreenNum. Invoke here as it was created on another thread
                MethodInvoker UpdateScreenNumButton = delegate { btnScreenNum.Text = Remote_Screen_Num + 1 + "/" + Remote_Num_Of_Screens; };
                Invoke( UpdateScreenNumButton );
            }
            catch( Exception ex )
            {
                DebugLog( "ShowClientScreen Exception: " + ex.Message.ToString( ) );
            }
        }


Что я уже пробовал:

Я зарегистрировал буфер скриншотов, который, кажется, составляет около 65535, поэтому подтвердил размер буфера, если его много.

Зарегистрировал информацию в конце техникума и все кажется в порядке

OriginalGriff

И что же? "Он разбился" - это не Информация - он ничего не говорит нам о том, что произошло, и мы не можем запустить ваш код изолированно, чтобы попытаться выяснить-мы понятия не имеем о более широком контексте приложения(ов) и о том, какие потоки они используют.

Итак, что вы сделали, чтобы выяснить, что происходит? Что показывает отладчик, что происходит? Вы пробовали им пользоваться? Какие сообщения вы получаете? что показывают ваши журналы?

Это не проблема, что мы можем сказать "это тот бит" просто из случайного чтения кода - это займет хорошее понимание того, что вы пытаетесь сделать и как это вписывается во всю систему.

Gerry Schmitz

Вы начинаете с самого минимального прототипа, который отправляет и получает небольшую картинку, и идете оттуда. В противном случае у тебя слишком много дел.

lmoelleb

Может быть, необработанное исключение? https://docs.microsoft.com/en-us/dotnet/api/system.appdomain.unhandledexception?view=netframework-4.8
И ваш оператор using работает только так, как ожидалось, с C# 8, поэтому убедитесь, что вы не компилируете с более старой языковой версией.
Кстати, 65535-это довольно подозрительно. Это максимальная длина, которая может быть представлена 16 битами и чрезвычайно мала для скриншота. Не знаю, где вы видите его 65535, но я бы его перепроверил.

Richard Deeming

foreach( Screen screen in Screen.AllScreens ) { NumOfScreens++; }

NB: То Экран.Свойство AllScreens[^] возвращает массив. Вы можете заменить эту петлю на:
NumOfScreens = Screen.AllScreens.Length;

sjsteve33171

Это удобно, спасибо!

sjsteve33171

Спасибо вам всем за комментарии до сих пор. Я потратил некоторое время, изучая его, и обнаружил, что это проблема с файлом app.manifest.

В основном я заметил, что при использовании чего-либо на экране масштабирования более 100%, например 150% или 200%, я получал изображение, которое было слишком большим для техника, чтобы видеть, и оно не подходило. Поставьте его на 100%, и он прекрасно работает. Поэтому я нашел статью, в которой объяснялось, как добавить в приложение следующее.manifest

<application xmlns="urn:schemas-microsoft-com:asm.v3">
  <windowsSettings>
    <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
  </windowsSettings>
</application>


Ясно, что это вызывает проблему. Если я его удалю, все будет в порядке и сработает. Я начинаю искать идеи, но если кто-то может направить меня в направлении обработки высокого DPI в скриншоте / приложении, я был бы признателен.

1 Ответов

Рейтинг:
1

Gerry Schmitz

using Graphics gfxScreenshot = Graphics.FromImage( bmpScreenshot );

using MemoryStream ms = new MemoryStream( imgData );

Эти "способы использования" используются "не по назначению". Вы "обертываете" его вокруг кода, который требует его области действия.

Прочтите раздел "Использование" и начните новый вопрос, если вам это нужно.


sjsteve33171

Я уже делал это раньше. Visual Studio говорит мне упростить его, сделав это

Gerry Schmitz

Вы правы, я устарел.