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.jpgm_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 initializationvoid 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形式保存的,也就是二进制文件保存的,所以,一定是可以传输。
最后上一张图片
欢迎大家拍砖,若发现错误,还望不忘拿起板砖,板砖,狠狠的拍向我。。。。。
另外:若转载,请标明出处,文章写的也是蛮累人的~ 谢谢大家....
QQ:2306798290