使用 C# 通过套接字发送和接收图像

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/749964/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 23:42:47  来源:igfitidea点击:

Sending and receiving an image over sockets with C#

c#sockets

提问by

I am trying to set up two programs in C#. Basically, a simple client server set up where I want the server to listen for an image from the client. Then, upon receiving the image, will display it in a PictureBox.

我正在尝试在 C# 中设置两个程序。基本上,设置了一个简单的客户端服务器,我希望服务器在其中侦听来自客户端的图像。然后,在接收到图像后,将其显示在 PictureBox 中。

I keep running into the following error:

我不断遇到以下错误:

A first chance exception of type 'System.ArgumentException' occurred in System.Drawing.dll

System.Drawing.dll 中发生了“System.ArgumentException”类型的第一次机会异常

The error is happening on the server code that is listening at this line: Image bmp = Image.FromStream(ms); Any ideas?

错误发生在正在侦听此行的服务器代码上:Image bmp = Image.FromStream(ms); 有任何想法吗?

The Server code that listens:

侦听的服务器代码:

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.IO;
using System.Net;
using System.Net.Sockets;

namespace NetView
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            startListening();
        }

        private void startListening()
        {
            ////////////////////////////////////////////

            Console.WriteLine("Server is starting...");
            byte[] data = new byte[1024];
            IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);

            Socket newsock = new Socket(AddressFamily.InterNetwork,
                            SocketType.Stream, ProtocolType.Tcp);

            newsock.Bind(ipep);
            newsock.Listen(10);
            Console.WriteLine("Waiting for a client...");

            Socket client = newsock.Accept();
            IPEndPoint newclient = (IPEndPoint)client.RemoteEndPoint;
            Console.WriteLine("Connected with {0} at port {1}",
                            newclient.Address, newclient.Port);

            while (true)
            {
                data = ReceiveVarData(client);
                MemoryStream ms = new MemoryStream(data);
                try
                {
                    Image bmp = Image.FromStream(ms);
                    pictureBox1.Image = bmp;
                }
                catch (ArgumentException e)
                {
                    Console.WriteLine("something broke");
                }


                if (data.Length == 0)
                    newsock.Listen(10);
            }
            //Console.WriteLine("Disconnected from {0}", newclient.Address);
            client.Close();
            newsock.Close();
            /////////////////////////////////////////////

        }

        private static byte[] ReceiveVarData(Socket s)
        {
            int total = 0;
            int recv;
            byte[] datasize = new byte[4];

            recv = s.Receive(datasize, 0, 4, 0);
            int size = BitConverter.ToInt32(datasize, 0);
            int dataleft = size;
            byte[] data = new byte[size];


            while (total < size)
            {
                recv = s.Receive(data, total, dataleft, 0);
                if (recv == 0)
                {
                    break;
                }
                total += recv;
                dataleft -= recv;
            }
            return data;
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

    }
}

The Client Code:

客户代码:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Drawing;
using System.IO;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            byte[] data = new byte[1024];
            int sent;
            IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050);

            Socket server = new Socket(AddressFamily.InterNetwork,
                            SocketType.Stream, ProtocolType.Tcp);

            try
            {
                server.Connect(ipep);
            }
            catch (SocketException e)
            {
                Console.WriteLine("Unable to connect to server.");
                Console.WriteLine(e.ToString());
                Console.ReadLine();
            }


            Bitmap bmp = new Bitmap("c:\eek256.jpg");

            MemoryStream ms = new MemoryStream();
            // Save to memory using the Jpeg format
            bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);

            // read to end
            byte[] bmpBytes = ms.GetBuffer();
            bmp.Dispose();
            ms.Close();

            sent = SendVarData(server, bmpBytes);

            Console.WriteLine("Disconnecting from server...");
            server.Shutdown(SocketShutdown.Both);
            server.Close();
            Console.ReadLine();
        }

        private static int SendVarData(Socket s, byte[] data)
        {
            int total = 0;
            int size = data.Length;
            int dataleft = size;
            int sent;

            byte[] datasize = new byte[4];
            datasize = BitConverter.GetBytes(size);
            sent = s.Send(datasize);

            while (total < size)
            {
                sent = s.Send(data, total, dataleft, SocketFlags.None);
                total += sent;
                dataleft -= sent;
            }
            return total;
        }
    }
}

回答by arul

ArgumentExceptiontells you that the image format in the stream is invalid. Which is probably caused by the client application closing the memory stream before the data were sent.

ArgumentException告诉您流中的图像格式无效。这可能是由于客户端应用程序在发送数据之前关闭了内存流造成的。

Try replacing byte[] bmpBytes = ms.GetBuffer();with

尝试替换byte[] bmpBytes = ms.GetBuffer();

byte[] bmpBytes = ms.ToArray();

Or close the stream after the data were sent.

或者在发送数据后关闭流。

Remember that the byte-array returned by the .GetBuffer()returns the underlying array, not a copy of it (.ToArray()returns a copy), that is valid as long as the parent stream.

请记住,返回的字节数组返回.GetBuffer()底层数组,而不是它.ToArray()的副本(返回副本),只要父流就有效。

回答by Jonathan Rupp

Use Arul's code to get the data to send correctly -- you want .ToArray(), not .GetBuffer(). Then, you'll want to run the server's 'startListening' method on a background thread or you won't actually see anything (as the form thread will be busy running the server code. Try:

使用 Arul 的代码来正确发送数据——您需要 .ToArray(),而不是 .GetBuffer()。然后,您需要在后台线程上运行服务器的“startListening”方法,否则您实际上看不到任何东西(因为表单线程将忙于运行服务器代码。尝试:

var t = new Thread(startListening);
t.IsBackground = true;
t.start();

In your Form_Load method instead of directly calling startListening in your constructor.

在您的 Form_Load 方法中,而不是在您的构造函数中直接调用 startListening。

回答by Lucas

If you have access to the JPG file itself (as in the example), you should send the file bytes and not use the Image/Bitmap classes. By reading a JPG file and re-encoding into JPG you are decreasing the image quality and incurring unnecessary overhead. You can use File.ReadAllBytes()to quickly get the complete byte[]or read/send it in pieces if your memory space is limited.

如果您有权访问 JPG 文件本身(如示例中所示),您应该发送文件字节而不是使用 Image/Bitmap 类。通过读取 JPG 文件并将其重新编码为 JPG,您会降低图像质量并产生不必要的开销。如果您的内存空间有限,您可以使用它File.ReadAllBytes()来快速获取完整byte[]或分段读取/发送。

回答by geometrikal

A better way to send the image would be to use BinaryFormatter.

发送图像的更好方法是使用 BinaryFormatter。

eg, some snippets from my own code to send an image every second...

例如,我自己代码中的一些片段每秒发送一张图像......

sending:

发送:

        TcpClient client = new TcpClient();  
        try  
        {    
            client.Connect(address, port); 

            // Retrieve the network stream.  
            NetworkStream stream = client.GetStream();  
            MessageData data = new MessageData(imageToSend); 

            IFormatter formatter = new BinaryFormatter();

            while(true)
            {
                formatter.Serialize(stream, data);
                Thread.Sleep(1000);
                data.GetNewImage();
            }    
        } 

receiving:

接收:

        TcpListener listener = new TcpListener(address, port);
        listener.Start();

        try
        { 
            using (TcpClient client = listener.AcceptTcpClient())
            {
                stream = client.GetStream();

                IFormatter formatter = new BinaryFormatter();
                while (true)
                {
                    MessageData data = (MessageData)formatter.Deserialize(stream);

                    if (ImageReceivedEvent != null) ImageReceivedEvent(data.Picture);
                }
            }
        }

and the MessageData class simply holds the image and has the [Serializable] attribute.

而 MessageData 类只是保存图像并具有 [Serializable] 属性。

回答by Süleyman Sümerta?

Here is a code that works for me. User starts server with a button and client selects photo by opening the file dialog of computer. At last sends the image but be careful about the photo size because UDP cannot transmit much large data.

这是一个对我有用的代码。用户通过一个按钮启动服务器,客户端通过打开计算机的文件对话框来选择照片。最后发送图像,但要注意照片大小,因为 UDP 无法传输大量数据。

Server:

服务器:

    delegate void showMessageInThread(string message);
    UdpClient listener = null;
    IPEndPoint endpoint = null;
    Thread listenThread = null;

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {

    }

    private void button1_Click(object sender, EventArgs e)
    {
        startServer();
    }
    private void startServer()
    {
        endpoint = new IPEndPoint(IPAddress.Any, 1234);
        listener = new UdpClient(endpoint);
        ShowMsg("Waiting for a client!");

        listenThread = new Thread(new ThreadStart(Listening));
        listenThread.Start();
    }
    private void Listening()
    {
        while (true)
        {
            //take the coming data
            byte[] comingDataFromClient = listener.Receive(ref endpoint);
            ImageConverter convertData = new ImageConverter();
            Image image =  (Image)convertData.ConvertFrom(comingDataFromClient);
            pictureBox1.Image = image;
        }
   private void ShowMsg(string msg)
   {
      this.richTextBox1.Text += msg + "\r\n";
   }

Client:

客户:

   Socket server = null;
    MemoryStream ms;
    IPEndPoint endpoint = null;
    public Form1()
    {
        InitializeComponent();
    }
    private void Form1_Load(object sender, EventArgs e)
    {
        server = new Socket(AddressFamily.InterNetwork,
            SocketType.Dgram, ProtocolType.Udp);
        endpoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1234);
    }
    private void btn_browse_Click(object sender, EventArgs e)
    {
        openFileDialog1.ShowDialog();
        string path = openFileDialog1.FileName;
        pictureBox1.Image = Image.FromFile(path);
        textPath.Text = path;
    }
    private void btn_send_Click(object sender, EventArgs e)
    {
        try
        {                
            ms = new MemoryStream();
            Bitmap bmp = new Bitmap(this.openFileDialog1.FileName);
            bmp.Save(ms, ImageFormat.Jpeg);
            byte[] byteArray = ms.ToArray();

            server.Connect(endpoint);
            server.SendTo(byteArray, endpoint);

            }
        }
        catch (Exception ex)
        {

        }