Проблема с отправкой пакетов 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 в скриншоте / приложении, я был бы признателен.