2

i made a client and server socket based gui app in which screen is captured and via socket it is transfered to desired listner but i am getting a black out put image a receiver end or client the image is there at server but cannot show it in my client app it just show a black pic?

code as : server

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.Net.Sockets;
using System.IO;
using System.Net;

namespace LanMonitoring
{
    public partial class Form1 : Form
    {
      private static Bitmap bmpScreenshot;
      bool start = false;
      private static Graphics gfxScreenshot;

      public Form1()
      {
        InitializeComponent();
        button2.Enabled = false;
      }

      private void button1_Click(object sender, EventArgs e)
      {           
        button1.Enabled = false;
        button2.Enabled = true;
        start = true;

        fillpic();
      }
      public void fillpic()
      {
        bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
        gfxScreenshot = Graphics.FromImage(bmpScreenshot);
        gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
        pictureBox1.Image = bmpScreenshot;
        sendbmp(bmpScreenshot);
      }


      private void button2_Click(object sender, EventArgs e)
      {

        button1.Enabled = true;
        button2.Enabled = false;
        start = false;
      }
      public void sendbmp(Bitmap bmp)
      {
        Socket mm = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(textBox1.Text), 5002);
        try
        {
          mm.Connect(remoteEP);
        }
        catch (Exception)
        {
          sendbmp(bmpScreenshot);
        }
        Image temp = bmp;
        byte[] buf = imageToByteArray(temp);
        mm.Send(buf);
        mm.Close();
     }
      public byte[] imageToByteArray(System.Drawing.Image imageIn)
      {
        MemoryStream ms = new MemoryStream();
        imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
        return ms.ToArray();
      }


      public Image byteArrayToImage(byte[] byteArrayIn)
      {
        MemoryStream ms = new MemoryStream(byteArrayIn);
        Image returnImage = Image.FromStream(ms);
        return returnImage;
      }

    }
}

client as:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.IO;
using System.Net;
namespace LanReciver
{
    public partial class Client : Form
    {

      byte[] buf = new byte[5000];
      public Client()
      {
        InitializeComponent();

      }

      private void button1_Click(object sender, EventArgs e)
      {
        backgroundWorker1.RunWorkerAsync();
      }
      public void call()
      {
        Socket mm = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        mm.Bind(new IPEndPoint(0, 5002));
        mm.Listen(100);
        Socket acc = mm.Accept();
        buf = new byte[acc.SendBufferSize];
        int byteread = acc.Receive(buf);
        byte[] rev = new byte[byteread];
        for (int i = 0; i < byteread; i++)
        {
          rev[i] = buf[i];
        }
        byteArrayToImage(rev);
        mm.Close();
        acc.Close();
        call();
      }

      public Image byteArrayToImage(byte[] byteArrayIn)
      {
        MemoryStream ms = new MemoryStream(byteArrayIn);
        Image returnImage = Image.FromStream(ms);
        return returnImage;
      }

      private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
      {
        call();
      }

      private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
      {
        MessageBox.Show("Recieved");
      }


    }
}
sarnold
  • 102,305
  • 22
  • 181
  • 238
user614946
  • 599
  • 5
  • 10
  • 27
  • Click: [`Select isn't broken`](http://pragprog.com/the-pragmatic-programmer/extracts/tips) – sehe Apr 04 '11 at 08:07

5 Answers5

3

Here's a reasonably complete (albeit quick and dirty) solution:

Server:

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;

namespace ImageServer
{
    static class Program
    {
        static void Main()
        {
            using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
            {
                socket.Bind(new IPEndPoint(IPAddress.Any, 23456));
                socket.Listen(100);
                while (true)
                {
                    using (var client = socket.Accept())
                    {
                        var bounds = Screen.PrimaryScreen.Bounds;
                        var bitmap = new Bitmap(bounds.Width, bounds.Height);
                        try
                        {
                            while (true)
                            {
                                using (var graphics = Graphics.FromImage(bitmap))
                                {
                                    graphics.CopyFromScreen(bounds.X, 0, bounds.Y, 0, bounds.Size);
                                }
                                byte[] imageData;
                                using (var stream = new MemoryStream())
                                {
                                    bitmap.Save(stream, ImageFormat.Png);
                                    imageData = stream.ToArray();
                                }
                                var lengthData = BitConverter.GetBytes(imageData.Length);
                                if (client.Send(lengthData) < lengthData.Length) break;
                                if (client.Send(imageData) < imageData.Length) break;
                                Thread.Sleep(1000);
                            }
                        }
                        catch
                        {
                            break;
                        }
                    }
                }
            }
        }
    }
}

Client (a form with a single button: "button1" and a single pictureBox: "pictureBox1"):

using System;
using System.Drawing;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;

namespace ImageClient
{
    public partial class Form1 : Form
    {
        private Bitmap _buffer;

        public Form1()
        {
            InitializeComponent();
        }

        private void Button1Click(object sender, EventArgs e)
        {
            button1.Enabled = false;
            ThreadPool.QueueUserWorkItem(GetSnapshots);
        }

        private void GetSnapshots(object state)
        {
            using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
            {
                socket.Connect(new IPEndPoint(IPAddress.Loopback, 23456));
                while (true)
                {
                    var lengthData = new byte[4];
                    var lengthBytesRead = 0;
                    while (lengthBytesRead < lengthData.Length)
                    {
                        var read = socket.Receive(lengthData, lengthBytesRead, lengthData.Length - lengthBytesRead, SocketFlags.None);
                        if (read == 0) return;
                        lengthBytesRead += read;
                    }
                    var length = BitConverter.ToInt32(lengthData, 0);
                    var imageData = new byte[length];
                    var imageBytesRead = 0;
                    while (imageBytesRead < imageData.Length)
                    {
                        var read = socket.Receive(imageData, imageBytesRead, imageData.Length - imageBytesRead, SocketFlags.None);
                        if (read == 0) return;
                        imageBytesRead += read;
                    }
                    using (var stream = new MemoryStream(imageData))
                    {
                        var bitmap = new Bitmap(stream);
                        Invoke(new ImageCompleteDelegate(ImageComplete), new object[] { bitmap });
                    }
                }
            }
        }

        private delegate void ImageCompleteDelegate(Bitmap bitmap);
        private void ImageComplete(Bitmap bitmap)
        {
            if (_buffer != null)
            {
                _buffer.Dispose();
            }
            _buffer = new Bitmap(bitmap);
            pictureBox1.Size = _buffer.Size;
            pictureBox1.Invalidate();
        }

        private void PictureBox1Paint(object sender, PaintEventArgs e)
        {
            if (_buffer == null) return;
            e.Graphics.DrawImage(_buffer, 0, 0);
        }
    }
}
Iridium
  • 23,323
  • 6
  • 52
  • 74
  • Your send function needs to check to see that the number of bytes you intended to be sent are actually sent. client.send might send part of your data, and you need to loop in the send until all bytes have been sent. Your use of the sleep is not clear. – aaaa bbbb Aug 03 '12 at 20:11
  • @aaaabbbb - No, it doesn't. The socket is in blocking mode (the default), and we are using a connection-oriented protocol (TCP), and so per the MSDN documentation for Socket.Send: "If you are using a connection-oriented protocol, Send will block until all of the bytes in the buffer are sent..." – Iridium Aug 03 '12 at 20:53
  • @aaaabbbb - The Sleep is used to provide a delay between sending of each "frame". – Iridium Aug 03 '12 at 20:54
  • Most of my socket programming pre-dates C#. Looks like you are right about the .NET implementation handling the looping until all bytes are sent. But consider the underlying socket library: "If no error occurs, send returns the total number of bytes sent, which can be less than the number requested to be sent in the len parameter." http://msdn.microsoft.com/en-us/library/windows/desktop/ms740149(v=vs.85).aspx – aaaa bbbb Aug 03 '12 at 21:10
  • @Iridium, i started a bounty to this your answer. I hope that you can help. – FLASHCODER Jan 04 '20 at 21:20
  • 1
    @BrowJr The image is already PNG compressed when it's sent, but if you're happy for the received image to not be a perfect reproduction of the source you could use a lossy image compression format to compress the image (e.g. JPEG) instead, and then adjust the quality to achieve the necessary bandwidth reductions for your scenario. Besides that you could also increase the time between frames (by increasing the `Thread.Sleep(...)`), or only capture a section of the screen instead of the whole thing. – Iridium Jan 06 '20 at 08:23
  • @Iridium, you says on answer that is a *`"reasonably complete (albeit quick and dirty) solution"`*. Then i want that you also, if possible, **showing all possible improvement that is missing** in a code edition (like requested on bounty). I'm using this code example in a particular project where not handle only screenshot but also with large strings, this is the reason to requesting improvements. – FLASHCODER Jan 06 '20 at 11:03
  • @BrowJr - StackOverflow is not a free code-writing service, if you have a particular problem, ask it as your own question, showing what you have already attempted yourself, and describing in detail what problems you are having and what you've done already to try and fix them. – Iridium Jan 06 '20 at 11:17
  • @Iridium, *"`Here's a reasonably complete`"**, only say what is missing to be a good and clean example? – FLASHCODER Jan 06 '20 at 15:16
  • 1
    @BrowJr It's an example of how to do *only* what the original asker wanted, it is "reasonably complete" in that it works, but is not intended to be a production-quality screen viewing app. In terms of what's "missing", there could be an infinite number of things depending on individual requirements, e.g. the ability to configure the port, host, authentication, authorization, update frequency, image compression, the screen area, displaying the mouse pointer location, viewer interaction, etc. Those might make it more "complete", but are *way* beyond the scope of a simple example in an SO answer. – Iridium Jan 06 '20 at 16:07
1

Just because you are sending the image with a single call to Send(...), it's very unlikely (unless the image is small, which if it's a screenshot, it probably isn't) that it will be received completely with a single call to Receive(...) on the client side.

You will need to call Receive(...) repeatedly, building up the received image buffer until Receive(...) returns 0, indicating that the socket has been closed. You should then have the complete image for display.

Iridium
  • 23,323
  • 6
  • 52
  • 74
  • This is the explanation of the mistakes/errors and a solution to it, instead of your other post only having code with not even comments in it. There sure was a reason why it's divided into 2 answers... – AmigoJack Oct 25 '22 at 22:11
0

Not sure what your actual problem is but I notice there is a potential bug in byteArrayToImage(); you must keep the stream open for the lifetime of the image (yeah, it's not the most usable .NET API method!): http://msdn.microsoft.com/en-us/library/93z9ee4x.aspx

Mitch Wheat
  • 295,962
  • 43
  • 465
  • 541
0

I used tcp client and listner method and it worked fine but with one prob on the reciver side it only shows the 1/4 of the image and throws an exception connection was not established .. now what is the prb

public partial class Form1 : Form { private static Bitmap bmpScreenshot; bool start = false; private static Graphics gfxScreenshot;

    public Form1()
    {
        InitializeComponent();
        button2.Enabled = false;
    }

    private void button1_Click(object sender, EventArgs e)
    {                   
        button1.Enabled = false;
        button2.Enabled = true;
        start = true;
        fillpic();
        backgroundWorker1.RunWorkerAsync();
    }
    public void fillpic()
    {
        bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
        gfxScreenshot = Graphics.FromImage(bmpScreenshot);
        gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
        pictureBox1.Image = bmpScreenshot;
     }


    private void button2_Click(object sender, EventArgs e)
    {

        button1.Enabled = true;
        button2.Enabled = false;
        start = false;
    }

    public byte[] imageToByteArray(System.Drawing.Image imageIn)
    {
        MemoryStream ms = new MemoryStream();
        imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
        return ms.ToArray();
    }



    public void caal()
    {
        TcpClient TCPC = new TcpClient();
        TCPC.Connect("127.0.0.1", 5002);
        if (TCPC.Connected)
        {
            NetworkStream ns = TCPC.GetStream();
            while (ns.CanWrite)
            {
                fillpic();
                byte[] data = imageToByteArray(bmpScreenshot);
                ns.Write(data, 0, data.Length);
            }
        }   
    }


    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        caal();
    }

    }
user614946
  • 599
  • 5
  • 10
  • 27
  • How are you delimiting the different images in this version? As far as I can see you're just sending screenshot after screenshot, but the receiver has no way to determine where one image ends and the next begins. – Iridium Apr 05 '11 at 05:41
  • thats what i need here but dont know how to ? – user614946 Apr 06 '11 at 16:22
  • One commonly used method would be to first write an integer indicating the number of bytes used by the next image, then write the image, then repeat the process for each following image. The client-side would then read the number, then continue reading until it had read the specified number of bytes and once it had, convert the buffer to an image and display it. It too would then repeat the process (read the number of bytes, then the image) for each following frame. – Iridium Apr 07 '11 at 00:51
0

Like @Iridium mentioned, you need to loop Read()-ing until no more data is received.

Also, please look at MemoryStream to replace all the array element shuffling. A simple Array.CopyTo would already be a vast improvent over the code you have to copy byte arrays

sehe
  • 374,641
  • 47
  • 450
  • 633