Socket 基础&实例(上)
2016-02-23 23:34
671 查看
Socket 基础知识
TCP/IP层次模型a. 应用层
b. 传输层 : UDP和TCP(区别即 TCP传输控制协议,是一种提供可靠数据传输的通用协议。
UDP是一个面 向无连接的协议,此处可能解释不太清楚,百度哈。(~ o ~)~zZ)
c. 网络层:通信子网,它通过网络连接交换传输层发出的实体数据。
d. 链路层:是建立在物理传输能力的基础上,以帧为单位传输数据,
它的主要任务就是进行数据封装和数据链接的建立
TCP分节传输图解
(每层传输过程中,都将增加分节的头)
Socket类型
a. 流式Socket
是一种面向连接的Socket,针对于面向连接的TCP服务应用,安全,但是效率低
b. 数据报式Socket
是一种无连接的Socket,对应于无连接的UDP服务应用,不安全,但效率高
组图说明Socket客户端和服务器的连接过程
这就是所谓的三次握手,哈哈。。
Socket常用类和方法
相关类:
IPAddress:包含了一个IP地址 IPEndPoint:包含了一对IP地址和端口号
方法:
Socket():创建一个Socket Bind():绑定一个本地的IP和端口号(IPEndPoint) Listen():让Socket侦听传入的连接吃那个病,并指定侦听队列容量 Connect():初始化与另一个Socket的连接 Accept():接收连接并返回一个新的Socket Send():输出数据到Socket Receive():从Socket中读取数据
上方法在Socket连接中基本上都会用到
实战部分代码
服务器代码(新建项目的时候,此处是
)
using System; using System.Net; using System.Collections.Generic; using System.Net.Sockets; using System.IO; using System.Text; using System.Threading; using System.Runtime.Serialization.Formatters.Binary; public class Echoserver { private static int m_SocketCount = 0; private static ManualResetEvent m_ManualResetEvent = new ManualResetEvent(false); //entry point of main method. public static void Main() { IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 10068); Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { serverSocket.Bind(ipEndPoint); serverSocket.Listen(20); Console.WriteLine("Server Start"); while (true) { m_ManualResetEvent.Reset(); //将线程置于非终止状态,也就是等待当前线程完成; serverSocket.BeginAccept(new AsyncCallback(Accept), serverSocket); m_ManualResetEvent.WaitOne(); //阻塞主线程,这里的作用是不退出程序; } } catch (System.Exception ex) { Console.WriteLine("Exception" + ex); } } public static void Accept(IAsyncResult result) { m_ManualResetEvent.Set(); //通知主线程继续; Socket serverSocket = (Socket)result.AsyncState; Console.WriteLine("Accept one Client " + (++m_SocketCount)); //已经Accept客户端之后就停止Accept; Socket receiverSocket = serverSocket.EndAccept(result); //开始Receive; StateObject state = new StateObject(); state.m_CurSocket = receiverSocket; receiverSocket.BeginReceive(state.m_Buffer, 0, StateObject.m_BufferSize, 0, new AsyncCallback(ReceiveCallBack), state); } public static void ReceiveCallBack(IAsyncResult result) { String content = String.Empty; StateObject state = (StateObject)result.AsyncState; Socket receiverSocket = state.m_CurSocket; try { int byteRead = receiverSocket.EndReceive(result); if (byteRead > 0) { //获取数据长度; byte[] datalengtharr = new byte[4]; Buffer.BlockCopy(state.m_Buffer, 0, datalengtharr, 0, 4); int datalength = BitConverter.ToInt32(datalengtharr, 0); Console.WriteLine("receive data length = " + datalength.ToString()); //获取数据主体; byte[] dataarr = new byte[byteRead - 4]; Buffer.BlockCopy(state.m_Buffer, 4, dataarr, 0, byteRead - 4); state.m_StringBuilder.Append(Encoding.ASCII.GetString(dataarr, 0, byteRead - 4)); content = state.m_StringBuilder.ToString(); //判断数据长度,是否接收完全; if (!(byteRead - 4 < datalength)) { Console.WriteLine("Receive " + content.Length + " " + content); //接收完全后发送数据给客户端; Send(receiverSocket, "success from server"); } else { //数据没有接收完,继续接收; receiverSocket.BeginReceive(state.m_Buffer, 0, StateObject.m_BufferSize, 0, new AsyncCallback(ReceiveCallBack), state); } } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } public static void Send(Socket handler, String data) { byte[] byteData = Encoding.ASCII.GetBytes(data); try { handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } public static void SendCallback(IAsyncResult result) { try { Socket handler = (Socket)result.AsyncState; int bytesSend = handler.EndSend(result); Console.WriteLine("Sent {0} bytes to client.", bytesSend); handler.Shutdown(SocketShutdown.Both); handler.Close(); } catch (System.Exception ex) { Console.WriteLine(ex.ToString()); } } public class StateObject { public Socket m_CurSocket = null; public const int m_BufferSize = 1024; public byte[] m_Buffer = new byte[m_BufferSize]; public StringBuilder m_StringBuilder = new StringBuilder(); } }
客户端代码
using UnityEngine; using UnityEngine.UI; using System.Collections; using System.Collections.Generic; using System; using System.Net; using System.Net.Sockets; using System.Text; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization; public class Test : MonoBehaviour { /// <summary> /// 连接到服务器 /// </summary> public void AsynConnect() { //端口及IP IPEndPoint ipe = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 10068); //创建套接字 Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //开始连接到服务器 client.BeginConnect(ipe, asyncResult => { client.EndConnect(asyncResult); //向服务器发送消息 DataMsg msg = new DataMsg(); msg.indexPos = 5; msg.name = "宏宇"; msg.sex = 1; List<string> otherPerList = new List<string>(); otherPerList.Add("小鸭"); otherPerList.Add("斗鸡"); otherPerList.Add("斗鸟"); msg.otherPerList.AddRange(otherPerList); //AsynSend(client, msg); AsynSend(client, "你好我是客户端"); //AsynSend(client, "第一条消息"); //AsynSend(client, "第二条消息"); //接受消息 AsynRecive(client); }, null); } /// <summary> /// 发送消息 /// </summary> /// <param name="socket"></param> /// <param name="message"></param> public void AsynSend(Socket socket, string message) { if (socket == null || message == string.Empty) return; //编码 byte[] data = Encoding.UTF8.GetBytes(message); try { socket.BeginSend(data, 0, data.Length, SocketFlags.None, asyncResult => { //完成发送消息 int length = socket.EndSend(asyncResult); Debug.Log(string.Format("客户端发送消息:{0}", message)); }, null); } catch (Exception ex) { Debug.Log(string.Format("异常信息:{0}", ex.Message)); } } public void AsynSend(Socket socket, DataMsg msgData) { if (socket == null || msgData == null) { return; } Debug.Log(msgData); MemoryStream mStream = new MemoryStream(); //BinaryFormatter bFormatter = new BinaryFormatter(); BinaryFormatter iFormatter = new BinaryFormatter(); //bFormatter.Serialize(mStream, msgData); //bFormatter.Serialize(mStream, "fff"); iFormatter.Serialize(mStream, msgData); mStream.Flush(); byte[] buffer = new byte[1024]; mStream.Position = 0; while (mStream.Read(buffer, 0, buffer.Length) > 0) { socket.Send(buffer); } socket.Close(); Debug.Log("数据发送完毕"); } /// <summary> /// 接收消息 /// </summary> /// <param name="socket"></param> public void AsynRecive(Socket socket) { byte[] data = new byte[1024]; try { //开始接收数据 socket.BeginReceive(data, 0, data.Length, SocketFlags.None, asyncResult => { int length = socket.EndReceive(asyncResult); Debug.Log(string.Format("收到服务器消息:{0}", Encoding.UTF8.GetString(data))); //AsynRecive(socket); }, null); } catch (Exception ex) { Debug.Log(string.Format("异常信息:", ex.Message)); } } void Awake() { gameObject.GetComponent<Button>().onClick.AddListener(delegate() { OnClickEvent(gameObject); }); } void OnClickEvent(GameObject target) { Debug.Log("Click" + target.name); AsynConnect(); } } [Serializable] public class DataMsg { public int indexPos; public int sex; public string name; public List<string> otherPerList; public DataMsg() { indexPos = 0; sex = 0; name = string.Empty; otherPerList = new List<string>(); } }
大家可能也注意到了我这里的客户端,留有传序列化的数据的方法,没错,本次实验只做传输数据,字符串简单的数据,后面会涉及多终端对一个服务器时的数据传输,等等,一直研究下去
如果有错误的地方,请指点,比较晚了,不好的下次再更新