Unity3d使用socket传输图片

文章转载自https://blog.csdn.net/qq_22393417/article/details/44752245;感谢原创 哈哈

C# socket通信只能传输的字节流,所以 我们若是想利用socket传输任何东西,都必须将之以字节的形式进行传输

So 本文就抛砖引玉一下,以传输图片的形式来示范一下,socket传输除文本数据以外的数据 嘻嘻~~~

既然是网络通信,那必然是有客户端和服务器端(通俗点说就是一发一收),那么就先说说客户端的那些事情吧!!!
(ps:如果,不知道客户端是什么的兄弟们,请不要往下看了,先去恶补恶补网络通信的一些知识)

在客户端,如果不说初始化socket那点事,那么,就只做一件事儿,就是将图片转换为字节数据,以便后边用Send函数进行传输,好吧,话不多说,直接上代码

private byte[] fssize; 
FileStream fs = new FileStream("D:/girl.jpg",FileMode.OpenOrCreate,FileAccess.Read);
Msg.fssize = new byte[fs.Length];
BinaryReader strread = new BinaryReader(fs);
strread.Read(Msg.fssize,0,Msg.fssize.Length);

上边4行代码做了这么几件事情:
1.定义一个需要被传输的字节数组fssize
2.创建FileStream对象,并基于该对象创建了BinaryReader对象
3.调用BinaryReader下的Read方法将数据读入fssize数组里边

当然,个个函数的具体参数是什么意思,我这里不展开阐述,查查MSDN就明白就可以了解的
我这里是将D盘的一张名为girl的图片转换为字节,这里要注意,要将图片的属性也写出来即D:/girl.jpg不能写成D:/girl

over 客户端就这样的over了,来我们接着说说服务器端,也就是接收端,同样接收端要是撇卡初始化的那点事儿,那么,也变得尤为的简洁了,也就是将接收到的数据还原为图片
当然,我这样说肯定很多人就默默的笑了,你不是废话的麽,肯定要还原的呀!!!哈哈 那就看看 如何还原的吧

//这里开辟了1M的字节空间 也就是一次图片的传输最大是1M大小
byte[] bytes = new byte[1024*1024];
int got = Soc_Temp.Receive(bytes);
// 将接受到的数据写入内存
MemoryStream fs = new MemoryStream();
fs.Write(bytes,0,got);
//使用Image类从内存中再次将数据读出来并保存为jpg图片
//注意 这里 无法保存在C盘
Image Img = Image.FromStream(fs);
Img.Save(desPathName,ImageFormat.Jpeg);
Debug.Log("保存完毕!!!");
//记得关闭流对象的哦
fs.Close();  

注意,这里使用Image类下的save方法,不能将数据保存在C盘,我之前就是在这里卡住了,切记.切记
同样的,每个函数具体是神马意思,我就不展开阐述的了,翻阅MSDN你知道会比我这里讲述的更多…Everybody know that!!!

OK,上边,上边只是讲了讲核心的部分,下边我将会将完整的代码贴出来,主要实现的一个功能是:客户端点击发送图片按钮,在服务器端的界面上就会显示该图片
那怎么做的呢?

我的做法是:将传输过来的图片保存在Asset下的Resources(没有的话自己创建一个)文件中,然后,使用Resources.Load方法动态的加载出来,当然,若有其他的途径欢迎拍砖,本人也是菜鸟一只,希望大家能多多的交流~嘎嘎…

下边就先贴出服务器端的代码 代码中也写好了注释,我这里是将套接字写在一个脚本中的,也因为服务器只有一个所以写的是一个单例类,接受数据是开启一个线程接受的

服务器 socket(套接字)脚本代码 服务器端的发送数据也写在其中的了,但, 我没有使用。注意这里需要引用的命名空间 特别注意的是如果 在写using System.Drawing提示找不

的时候,需要将System.Drawing.dll文件拷贝到当前工程中来

using UnityEngine;
using System.Collections;
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Drawing.Imaging;
using System.Drawing;
using System.Net;
using System.IO;
using System.Threading;
 
 
//单例类
public class ser  {
 
	private static ser serInstance = null;
 
	private ser()
	{
 
	}
 
	public static ser GetInstance()
	{
		lock(lockHelper)
		{
			if( serInstance == null )
			{
				serInstance = new ser();
			}
			return serInstance;
		}
	}
 
	private Socket Soc_Temp;
	private TcpListener tcpLister;
	private bool live = true;
	private bool abort_Start=false;
	private bool abort_Get=false;
	private bool abort_Send=false;
	
	public string send_Mes = "send_Mes";
	public string get_Mes = "get_Mes";
	
	Thread Thread_Start;
	Thread Thread_getData;
	Thread Thread_sendData;
 
	private static object lockHelper = new object();
 
	//图片保存的地址与名字
	private string desPathName = Application.dataPath + "/Resources/girl.jpg";
 
	public bool beSave = false;
	
	public void Server_Start()
	{
		begin();
	}
	
	void begin()
	{
		//把/转换为\ 这是因为 Image保存时的路径需要的是\
		//而Application.dataPath的路径中是/
		desPathName.Replace("/","\\");
		Debug.Log(desPathName);
 
		abort_Start = true;
		tcpLister = new TcpListener(IPAddress.Any,8080);
		tcpLister.Start();
		Thread_Start = new Thread(Start);
		Thread_Start.IsBackground = true;
		Thread_Start.Start();
		Debug.Log("线程开启状态Thread_Start="+Thread_Start.ThreadState);
		Debug.Log("线程开启状态Thread_Start="+Thread_Start.IsAlive);
	}
 
	//TCP连接  并且 开启一个函数线程专门用于接收数据
	void Start()
	{
		while(live)
		{
			try
			{
				if(tcpLister.Pending())
				{
					abort_Get = true;
					Soc_Temp = tcpLister.AcceptSocket();
					Thread_getData = new Thread(getData);
					Thread_getData.IsBackground = true;
					Thread_getData.Start();
					Debug.Log("线程接收状态Thread_getData="+Thread_getData.ThreadState);
					Debug.Log("线程接收状态Thread_getData="+Thread_getData.IsAlive);
				}
			}
			catch(Exception e)
			{
				Debug.Log(e.Data.ToString());
 
				Soc_Temp.Close();
				Soc_Temp = null;
				live = false;
				tcpLister.Stop();
				Thread_getData.Abort();
			}
		}
	}
 
	//接收数据线程函数
	void getData()
	{
		while(live)
		{
			try
			{
				//避免在多线程下数据接收错误
				lock(lockHelper)
				{
 
					//这里开辟了1M的字节空间 也就是一次图片的传输最大是1M大小
					byte[] bytes = new byte[1024*1024];
					int got = Soc_Temp.Receive(bytes);
					// 将接受到的数据写入内存
					MemoryStream fs = new MemoryStream();
					fs.Write(bytes,0,got);
 
					//从内存中再次将数据读出来并保存为jpg图片
					//注意 这里 无法保存在C盘
					Image Img = Image.FromStream(fs);
					Img.Save(desPathName,ImageFormat.Jpeg);
					Debug.Log("保存完毕!!!");
					beSave = true;
					fs.Close();
 
				}
				
			}
			catch(Exception e)
			{
				Debug.Log(e.Data.ToString());
 
				live = false;
				Soc_Temp.Close();
				Soc_Temp = null;
				Thread_getData.Abort();
			}
		}
	}
 
	//发送数据 线程函数
	public void SendM()
	{
		abort_Send = true;
		Thread_sendData = new Thread(sendData);
		Thread_sendData.IsBackground = true;
		Thread_sendData.Start();
		
		Debug.Log("线程发送状态Thread_Start="+Thread_sendData.ThreadState);
		Debug.Log("线程发送状态Thread_Start="+Thread_sendData.IsAlive);
	}
 
	//发送数据
	void sendData()
	{
		try
		{
			byte[] send_bytes = Encoding.UTF8.GetBytes(send_Mes);
			Soc_Temp.Send(send_bytes);
		}
		catch(Exception e)
		{
			Debug.Log(e.Data.ToString());
 
			live = false;
			Soc_Temp.Close();
			Soc_Temp = null;
			Thread_getData.Abort();
		}
	}
	
	//终止线程
	public void setAbort()
	{
		if( abort_Start )
		{
			Thread_Start.Abort();
			Debug.Log("开启状态Thread_Start="+Thread_Start.ThreadState);
			Debug.Log("开启状态Thread_Start="+Thread_Start.IsAlive);
			abort_Start = false;
		}
		if( abort_Get )
		{
			Thread_getData.Abort();
			Debug.Log("接受状态Thread_getData="+Thread_getData.ThreadState);
			Debug.Log("接受状态Thread_getData="+Thread_getData.IsAlive);
			abort_Get = false;
		}
		if( abort_Send )
		{
			Thread_sendData.Abort();
			Debug.Log("发送状态Thread_sendData="+Thread_sendData.ThreadState);
			Debug.Log("发送状态State:Thread_sendData="+Thread_sendData.IsAlive);
			abort_Send = false;
		}
	}
	
}

下边贴出 真正做事的那个脚本

也就是这个脚本中的代码将会去调用上边的脚本,直接上代码,大家就会一目了然的了

using UnityEngine;
using System.Collections;
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Drawing.Imaging;
using System.Drawing;
using System.Net;
using System.IO;
 
public class setServer : MonoBehaviour {
 
	ser m_ser;
 
	Texture2D m_Texure;
 
	void Start()
	{
		m_ser = ser.GetInstance();
	}
 
	void OnDestroy()
	{
		print(" 脚本以关闭");
 
		m_ser.setAbort();
	}
 
	void OnGUI()
	{
		//开启服务器
		if( GUI.Button(new Rect((Screen.width/2)-50,(Screen.height/2),100,30),"开启服务器") )
		{
			m_ser.Server_Start();
		}
 
		//图过图片已经传输过来并且保存在了指定的位置
		if( m_ser.beSave )
		{
			//Load方法加载Resource文件夹下的资源girl不用写成girl.jpg
			m_Texure = Resources.Load("girl") as Texture2D;
			if(m_Texure != null)	
			{
				GUI.DrawTexture(new Rect(0,0,m_Texure.width,m_Texure.height),m_Texure);
			}
		}
 
	}
}

可以看到,在这个脚本中,将传输过来的图片Load出来,然后使用GUI.DrawTexture方法贴出来

OK,OK,OK,服务器端就这么Over了,那么接着看看客户端的代码

using UnityEngine;
using System.Collections;
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.IO;
 
public class client : MonoBehaviour {
 
 
	private Socket clientMsg;
 
	struct sendDate
	{
		public byte[] fssize;
	};
	private sendDate Msg;
 
	// Use this for initialization
	void Start ()
	{
		IPEndPoint ipendpiont = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080); 
		clientMsg = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
		clientMsg.Connect(ipendpiont);
	}
	
	void OnGUI()
	{
		if(GUI.Button(new Rect(Screen.width/2,0,100,50),"发送图片"))
		{
			//声明一个文件流对象fs,并实例化该对象
			FileStream fs = new FileStream("D:/girl.jpg",FileMode.OpenOrCreate,FileAccess.Read);
			//为了防止socket连接出现异常,所以使用try...catch语句 
			try
			{
				//下边三行代码是 将fs对象所操作的图片转换为字节数据,并保存在Msg.fssize数组中
				Msg.fssize = new byte[fs.Length];
				BinaryReader strread = new BinaryReader(fs);
				strread.Read(Msg.fssize,0,Msg.fssize.Length);
				//发送数据
				clientMsg.Send(Msg.fssize);
			}
			catch(SocketException e)
			{
				Debug.Log(e.Data.ToString());
 
				fs.Close();
				clientMsg.Shutdown(System.Net.Sockets.SocketShutdown.Send);
				clientMsg.Close();
				clientMsg = null;
				
			}
 
		}
	}
 
	void OnDestroy()
	{
		clientMsg.Close();
	}
	
}

同样,代码还是比较简洁的,那么至此,整个过程就算是完成了,大家可以尝试一下

当然,这个只是传输图片的,也可以传输视频,音频等文件,虽然,我还没有去尝试,但是,一定是可以的,因为,我们所有的东西在电脑上都是以010101形式保存的,也就是二进制文件保存的,所以,一定是可以传输。

最后一张图
在这里插入图片描述

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值