Right now I only need to be able to send a 100kb JPEG photo. I tried Google and found a couple of things but their code only threw exceptions so maybe what they've done is not appropriate in my situation.

This is an attempt at a remote screen viewer. If you're sharing your screen, I start a TcpListener on a random port and display the IP the viewer must use to connect to you. If you're a viewer, you type in the IP and port you want and it sends a request to connect by TcpClient.

That's all I've got to. Here's some code.

Connecting to a client:

private TcpClient MasterConnectionClient = new TcpClient();

private void ConnectButton_Click(object sender, EventArgs e)
        {
            string[] ConnectionInfo = ConnectToIPAddressBox.Text.Split(':');

            try
            {
                MasterConnectionClient.Connect(IPAddress.Parse(ConnectionInfo[0]), int.Parse(ConnectionInfo[1]));

                ViewportForm VPF = new ViewportForm();
                this.Hide();

                VPF.ShowDialog(); //Shows the form that will display the screenshot
            }

            catch (Exception E)
            {
                MessageBox.Show(E.Message, E.GetType().ToString());
            }

Client waiting for connection

int Port = new Random().Next(1, 65535);

            ClientSide.MasterListener = new TcpListener(IPAddress.Any, Port);
            ConnectionAddressLabel.Text = GetExternalIP() + ":" + Port.ToString();
        
private void ShareButton_Click(object sender, EventArgs e)
        {
            CurrentOperationLabel.Text = "Waiting for connection...";

            new Thread(new ThreadStart(
                delegate
                {
                    ClientSide.MasterListener.Start();
                    ClientSide.MasterSocket = ClientSide.MasterListener.AcceptSocket();

                    ScreenViewerIPLabel.Invoke(new ThreadStart(
                            delegate
                            {
                                ScreenViewerIPLabel.Text = ClientSide.MasterSocket.RemoteEndPoint.ToString();
                            }));
                })).Start();
        }

And this is what I've picked out from Google on getting and sending the screenshot. I don't understand line 12 and down. It throws an exception that says "A request to send or receive data was disallowed because the socket was not connected." ???

public static void SendScreenshot()
        {
            int screenWidth  = Screen.GetBounds(new Point(0, 0)).Width;
            int screenHeight = Screen.GetBounds(new Point(0, 0)).Height;

            Bitmap bmpScreenShot = new Bitmap(screenWidth, screenHeight);
            Graphics gfx = Graphics.FromImage((Image)bmpScreenShot);

            gfx.CopyFromScreen(0, 0, 0, 0, new Size(screenWidth, screenHeight));
            bmpScreenShot.Save(@"C:\WINDOWS\Temp\RV\screentest.jpeg", ImageFormat.Jpeg);

            byte[] fileNameByte = Encoding.ASCII.GetBytes("screentest.jpeG");
            byte[] fileData     = File.ReadAllBytes(@"C:\WINDOWS\Temp\RV\screentest.jpeg");
            byte[] fileNameLen  = BitConverter.GetBytes(fileNameByte.Length);
            byte[] clientData = new byte[4 + fileNameByte.Length + fileData.Length];

            fileNameLen.CopyTo(clientData, 0);
            fileNameByte.CopyTo(clientData, 4);
            fileData.CopyTo(clientData, 4 + fileNameByte.Length);

            MasterSocket.Send(clientData);
        }

I'm not completely sure on this, but my first thoughts are that since you're opening the socket and accepting a connection in a new thread, it would cause the main thread to throw a "not connected" exception since it's in a different context... but that could be completely wrong.

Some things you can do right away however:
Once you've hit the ShareButton and your server is waiting for a connection, open up a command prompt and run 'netcat'. Netcat will show you all the open ports/sockets on your computer and what state they're in. Make sure that the port you bound your socket to is listed in the output, and that the state says "LISTENING". Once you've verified that the socket is in fact listening for connections, have your client connect to it then run netcat again. The state should have changed to ESTABLISHED. If it is established, then there is some problem in the way your server program attempts to communicate with the socket (like a contextual error perhaps?).

If however it's not establishing correctly, you could be running into a firewall problem. Since you're randomly picking a port from 1 to 65535 you're including the "reserved" ports. They're not reserved in the sense that you're not allowed to use them, just that they've been agreed upon to represent specific services. For example, if you ended up with port 22, it is "assumed" that the service running there is an SSH server. Port 80 would be http, 443 https, 25 SMTP, etc. This is significant because your firewall is most likely configured to block those connections unless you've specifically opened them. Assuming you're testing this on a local network, or even the same machine, then you'd only have to worry about one firewall, the host's own firewall.

I'm not certain on how Random.Next() generates a "random" number, as in if it internally uses a new seed each time its run. If it doesn't and you end up with the same "random" port every time you run the program then it's possible you're getting the same port blocked every time.

To try and explain the part you didn't understand

byte[] fileNameByte = Encoding.ASCII.GetBytes("screentest.jpeG");
            byte[] fileData     = File.ReadAllBytes(@"C:\WINDOWS\Temp\RV\screentest.jpeg");
            byte[] fileNameLen  = BitConverter.GetBytes(fileNameByte.Length);
            byte[] clientData = new byte[4 + fileNameByte.Length + fileData.Length];
 
            fileNameLen.CopyTo(clientData, 0);
            fileNameByte.CopyTo(clientData, 4);
            fileData.CopyTo(clientData, 4 + fileNameByte.Length);
 
            MasterSocket.Send(clientData);

This more or less describes a protocol for sending a jpeg. The byte[] declarations set up the physical data to be sent across the wire. clientData is what will be the final byte[] that is sent, and how it is created is your "protocol". The first 4 bytes are an integer value representing the length of the file name:

fileNameLen.CopyTo(clientData, [B]0[/B]);

Next comes the name of the file, which starts at the 5th byte:

fileNameByte.CopyTo(clientData, [B]4[/B]);

Finally the actual file data is copied, but its offset has to be calculated since you don't know how long the filename is:

fileData.CopyTo(clientData, [B]4 + fileNameByte.Length[/B]);

And finally once the data is ready it's sent. I say it's a protocol because it's an agreed upon structure for the data. Since only pure data is sent, and no description of the data, there has to be a known structure so on the receiving end you know that the first 4 bytes are the filename length, the following [filename length] bytes are the filename, and the reamining bytes are the data. Otherwise you'd have no idea how to decode the data that you've received.

Hope some of that helps!

Comments
Excellent!

Thank you! That's the kind of post I was looking for. :)

I don't seem to have something called 'netcat'. It says 'not recognized as an internal or external command blah blah blah'. I'm on XP SP3 if that matters. Either way, it seems that I can successfully connect the two programs because when a connection is established I show the IP address of the other computer (RemoteEndpoint?). The only time I try to send data is when I send the screenshot so it's probably something with how I use the socket. I'll work with that awhile.

Random.Next() says 'returns a random number within the specified range'. I believe that most of the random ports have been very very high numbers. I've changed that to 2000 and 3000 as I didn't know about reserved ports. Maybe I need to check if the port can be used first or something? Can I do that?

Fantastic explanation by the way. Maybe a stupid question but do I need to send the file's name or can I just receive the raw file data and write it to a file with a name of my own choosing?

Edited 5 Years Ago by WildBamaBoy: n/a

I know you solved this already, but I just had to mention that I told you to use the wrong tool! Netcat is for something entirely different. netstat is what I meant. That's what lists the open ports etc.

Sorry! But I'm glad you figured everything out!

This question has already been answered. Start a new discussion instead.