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

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

我一直遇到以下错误:

System.Drawing.dll中发生了’System.ArgumentException’类型的第一次机会exception

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

侦听的服务器代码:

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) { } } } 

客户代码:

 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; } } } 

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

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

 byte[] bmpBytes = ms.ToArray(); 

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

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

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

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

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

发送:

  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(); } } 

接收:

  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); } } } 

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

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

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

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

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

服务器:

  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"; } 

客户:

  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) { }