网络通讯之Socket-Tcp(一)
网络通讯之Socket-Tcp 分成2部分讲解:
网络通讯之Socket-Tcp(一):
1.如何理解Socket
2.Socket通信重要函数
3.Socket Tcp 调用的基本流程图
4.简单Socket实例
1.完善Socket实例【黏包拆包 收发数据】
2.优化Socket
3.Socket网络安全
Socket(套接字)是干什么的?应用层和传输层 的中转台或者说是桥梁。
什么是应用层,比如我们手机上的QQ应用、微信应用、和平精英、lol手游 都属于应用层。
怎么理解socket?
可以理解为是一种数据结构,数据结构主要包括:发送缓存区、接收缓存区、再加控制参数。
常用的socket 用三种类型:
1.TCP:流式socket ,面向连接、字节流传输、点对点、可靠的服务【丢失操作系统会自动重传】
2.UDP:数字报socket、无连接、不可靠【数据丢失不会重传】
3.RAW:原始socket
服务机:一个服务器程序能够接收客户端的连接请求,必有一个Socket(套接字)在等待别人的连接请求。
客户机:向服务器发送连接之前 也必须创建一个Socket(套接字)、还需要指定服务器进程的Ip地址、端口号。
Socket通信重要函数:
Scoket TCP 调用的基本流程:
简单Socket实例
实例上图
C# Socket 服务器代码:
ping一下拿到我们本机地址
1 using System;
2 using System.Net;
3 using System.Net.Sockets;
4 using System.Threading;
5
6 namespace ZhaoBuHui.GateWayServer
7 {
8 public sealed class ServerConfig
9 {
10 public static string ip = "192.168.124.2";
11 public static int point = 8082;
12 }
13
14 class Program
15 {
16 private static Socket m_ListenSocket;
17 static void Main(string[] args)
18 {
19 Console.WriteLine("Hello World!");
20 StartListen();
21 }
22 public static void StartListen()
23 {
24 m_ListenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
25 m_ListenSocket.Bind(new IPEndPoint(IPAddress.Parse(ServerConfig.ip), ServerConfig.point));
26 m_ListenSocket.Listen(100);
27 Console.WriteLine("启动监听{0}成功", m_ListenSocket.LocalEndPoint.ToString());
28 Thread thread = new Thread(ListenClientConnect);
29 thread.Start();
30 }
31 /// <summary>
32 /// 监听客户端链接
33 /// </summary>
34 /// <param name="obj"></param>
35 private static void ListenClientConnect(object obj)
36 {
37 while (true)
38 {
39 try
40 {
41 Socket m_ClientSocket = m_ListenSocket.Accept();
42 IPEndPoint iPEndPoint = (IPEndPoint)m_ClientSocket.RemoteEndPoint;
43 Console.WriteLine("收到客户端IP={0},Port={1}已经连接", iPEndPoint.Address.ToString(), iPEndPoint.Port.ToString());
44
45 string str = "赵不灰就是赵老三";
46 byte[] data = System.Text.Encoding.UTF8.GetBytes(str);
47 m_ClientSocket.BeginSend(data, 0, data.Length, SocketFlags.None, (IAsyncResult ar) =>
48 {
49 int len = m_ClientSocket.EndSend(ar);
50 if (len > 0)
51 {
52 Console.WriteLine("Send Success!字节数 = " + len);
53 }
54 }, m_ClientSocket);
55 }
56 catch (Exception ex)
57 {
58 Console.WriteLine(ex.ToString());
59 }
60 }
61 }
62 }
63 }
客户端代码:
TestSocketTcpRoutine.cs SocketTcp访问器
1 using System;
2 using System.Net;
3 using System.Net.Sockets;
4
5 public class TestSocketTcpRoutine
6 {
7 private Socket m_ClientSocket;
8
9 // 是否连接过socket
10 private bool m_bDoConnect;
11 // 是否连接成功
12 private bool m_IsConnectSuccess;
13 private Action<bool> m_ConnectCompletedHander;
14
15 /// <summary>
16 /// 接收数据缓存区
17 /// </summary>
18 private byte[] m_Receive = new byte[1024];
19 private TestMemoryStreamUtil m_ReceiveMS = new TestMemoryStreamUtil();
20
21 public void Connect(string ip, int point, Action<bool> bConnectComplete)
22 {
23 m_ConnectCompletedHander = bConnectComplete;
24 if ((m_ClientSocket != null && m_ClientSocket.Connected) || m_IsConnectSuccess)
25 {
26 return;
27 }
28 m_IsConnectSuccess = false;
29 try
30 {
31 m_ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
32 m_ClientSocket.BeginConnect(new IPEndPoint(IPAddress.Parse(ip), point), ConnectCallBack, m_ClientSocket);
33 }
34 catch (Exception ex)
35 {
36 m_ConnectCompletedHander?.Invoke(m_IsConnectSuccess);
37 UnityEngine.Debug.LogError(ex.ToString());
38 }
39 }
40
41 private void ConnectCallBack(IAsyncResult ar)
42 {
43 m_bDoConnect = true;
44 if (m_ClientSocket.Connected)
45 {
46 ReceiveMsg();
47 m_IsConnectSuccess = true;
48 }
49 else
50 {
51 m_IsConnectSuccess = false;
52 UnityEngine.Debug.LogError("服务器断开链接");
53 }
54 m_ClientSocket.EndConnect(ar);
55 }
56
57 public void OnUpdate()
58 {
59 if (m_bDoConnect)
60 {
61 m_bDoConnect = false;
62 m_ConnectCompletedHander?.Invoke(m_IsConnectSuccess);
63 }
64 if (!m_IsConnectSuccess) return;
65 }
66
67 //接收消息
68 private void ReceiveMsg()
69 {
70 try
71 {
72 //开始接收
73 m_ClientSocket.BeginReceive(m_Receive, 0, m_Receive.Length, SocketFlags.None, (IAsyncResult ar) =>
74 {
75 try
76 {
77 int len = m_ClientSocket.EndReceive(ar);
78 if (len > 0)
79 {
80 UnityEngine.Debug.Log("收到字节数 = " + len);
81 m_ReceiveMS.Position = m_ReceiveMS.Length;
82 m_ReceiveMS.Write(m_Receive, 0, len);
83 byte[] temp = new byte[len];
84 m_ReceiveMS.Position = 0;
85 m_ReceiveMS.Read(temp, 0, len);
86 string str = System.Text.Encoding.UTF8.GetString(temp);
87 UnityEngine.Debug.Log(str);
88 }
89 else
90 {
91 UnityEngine.Debug.Log("没有收到数据 ");
92 }
93 }
94 catch (Exception ex)
95 {
96 UnityEngine.Debug.LogError(ex.ToString());
97 }
98 }, m_ClientSocket);
99 }
100 catch (Exception ex)
101 {
102 UnityEngine.Debug.LogError(ex.ToString());
103 }
104 }
105 }
TestMemoryStreamUtil 不知道的请点击访问
m_ConnectCompletedHander 不管连接成功失败 我们都需要知道结果 进行下一步处理
TestSocketManager.cs Socket管理器
1 public class TestSocketManager : System.IDisposable
2 {
3 public TestSocketTcpRoutine m_MainSocket;
4 public void Init()
5 {
6 m_MainSocket = CreateSocketTcpRoutine();
7 }
8 public void Connect(string ip, int point, System.Action<bool> connectComplete)
9 {
10 m_MainSocket.Connect(ip, point, connectComplete);
11 }
12 public TestSocketTcpRoutine CreateSocketTcpRoutine()
13 {
14 return TestGameEntry.PoolMgr.Class_Dequeue<TestSocketTcpRoutine>();
15 }
16
17 public void Update()
18 {
19 if (m_MainSocket != null)
20 {
21 m_MainSocket.OnUpdate();
22 }
23 }
24
25 public void Dispose()
26 {
27
28 }
29 }
Class_Dequeue 不知道的请点击访问
TestGameEntry.cs 游戏入口
1 using UnityEngine;
2
3 public class TestGameEntry : MonoBehaviour
4 {
5 public static TestGameEntry Instance;
6 public static TestTimeManager TimeMgr { get; private set; }
7 public static TestPoolManager PoolMgr { get; private set; }
8 public static TestFsmManager FsmMgr { get; private set; }
9 public static TestProcedureManager ProcedureMgr { get; private set; }
10 public static TestHttpManager HttpMgr { get; private set; }
11 public static TestEventManager EventMgr { get; private set; }
12 public static TestSocketManager SocketMgr { get; private set; }
13
14
15 private void Awake()
16 {
17 Instance = this;
18 }
19
20 void Start()
21 {
22 InitManagers();
23 Init();
24 }
25
26 void InitManagers()
27 {
28 TimeMgr = new TestTimeManager();
29 PoolMgr = new TestPoolManager();
30 FsmMgr = new TestFsmManager();
31 ProcedureMgr = new TestProcedureManager();
32 HttpMgr = new TestHttpManager();
33 EventMgr = new TestEventManager();
34 SocketMgr = new TestSocketManager();
35 }
36
37 void Init()
38 {
39 TimeMgr.Init();
40 PoolMgr.Init();
41 FsmMgr.Init();
42 ProcedureMgr.Init();
43 HttpMgr.Init();
44 EventMgr.Init();
45 SocketMgr.Init();
46 }
47
48 void Update()
49 {
50 TimeMgr.OnUpdate();
51 PoolMgr.OnUpdate();
52 ProcedureMgr.OnUpdate();
53 SocketMgr.Update();
54 }
55
56 private void OnDestroy()
57 {
58 TimeMgr.Dispose();
59 PoolMgr.Dispose();
60 FsmMgr.Dispose();
61 ProcedureMgr.Dispose();
62 HttpMgr.Dispose();
63 EventMgr.Dispose();
64 SocketMgr.Dispose();
65 }
66 }
TestGameEntry 不知道的请点击访问
测试代码: 按A进行连接服务器
1 if (Input.GetKeyDown(KeyCode.A))
2 {
3 TestGameEntry.SocketMgr.Connect("192.168.124.2", 8082, (bool isConnectSuccess) =>
4 {
5 UnityEngine.Debug.Log("连接192.168.124.2:8082" + (isConnectSuccess ? "成功" : "失败"));
6 });
7 }
注意事项:
1. BeginConnect EndConnect 成对出现
2.BeginReceive EndReceive 成对出现