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>();
}
}
大家可能也注意到了我这里的客户端,留有传序列化的数据的方法,没错,本次实验只做传输数据,字符串简单的数据,后面会涉及多终端对一个服务器时的数据传输,等等,一直研究下去
如果有错误的地方,请指点,比较晚了,不好的下次再更新