Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

同步方法UDP服务端实现示例

注意: 这里的示例只是示例,仅供学习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
public class SeverSocket
{
private Socket socket;

private bool isClosed;

//我们可以通过记录谁给我发送了消息 把它的 IP和端口记录下来 这样就认为它是我的客户端

private Dictionary<string,Client> clientDic = new Dictionary<string,Client>();
public void Start(string ip, int port)
{
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(ip), port);
//声明udp通信的socket
socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
try
{
socket.Bind(ipEndPoint);
isClosed = false;
//消息处理
ThreadPool.QueueUserWorkItem(ReceiveMsg);
}
catch (Exception e)
{
Console.WriteLine("UDP开启出错"+e.Message);
throw;
}
}

private void CheckTimeout(object obj)
{
long nowTime = 0;
while (true)
{
//每30秒检测一次
Thread.Sleep(30000);
nowTime = DateTime.Now.Ticks/TimeSpan.TicksPerSecond;
List<string> delList = new List<string>();
foreach (var c in clientDic.Values)
{
//超过10秒没有收到消息的客户端消息需要被移除
if (nowTime - c.frontTime >= 10)
{
delList.Add(c.clinetStrID);
}
}
for (int i = 0; i < delList.Count; i++)
RemoveClinet(delList[i]);
delList.Clear();
}
}
private void ReceiveMsg(object state)
{
//接收消息得到容器
byte[] bytes = new byte[512];
//记录谁发的消息
EndPoint ipPoint = new IPEndPoint(IPAddress.Any, 0);
//用于拼接字符串 字典ID 是由 IP+端口构成的
string strID = "";
string ip;
int port;
while (isClosed)
{
if (socket.Available>0)
{
lock (socket)
socket.ReceiveFrom(bytes, ref ipPoint);
//处理消息最好不要在这里处理 而是交给客户端处理
//收到消息时 我们可以来判断 是不是记录了这个客户端信息(ip和端口)
//取出发送消息给我的 IP和端口
ip = (ipPoint as IPEndPoint).Address.ToString();
port = (ipPoint as IPEndPoint).Port;
strID = ip + port;//拼接成一个唯一ID
//判断有没有记录这个客户端消息 如果有 用它直接处理消息
if (clientDic.ContainsKey(strID))
clientDic[strID].ReceiveMsg(bytes);
else//如果没有 直接添加并处理消息
{
clientDic.Add(strID,new Client(ip,port));
clientDic[strID].ReceiveMsg(bytes);
}
}
}
}
//指定发送一个消息给某个目标
public void SendTo(BaseMsg baseMsg, IPEndPoint ipPoint)
{
try
{
lock (socket)
socket.SendTo(baseMsg.Writing(), ipPoint);
}
catch (SocketException e)
{
Console.WriteLine("发消息出现问题" +e.ErrorCode+ e.Message);
}
catch (Exception e)
{
Console.WriteLine("序列化出问题" + e.Message);
}
}
//广播消息
public void BoradcastTo(BaseMsg baseMsg)
{
foreach (var c in clientDic.Values)
{
SendTo(baseMsg,c.clientAndpoint);
}
}
public void Close()
{
if (socket != null)
{
isClosed = true;
socket.Shutdown(SocketShutdown.Both);
socket.Close();
socket=null;
}
}
public void RemoveClinet(string clientID)
{
if (clientDic.ContainsKey(clientID))
{
Console.WriteLine("客户端{0}被移除了",clientDic[clientID].clientAndpoint);
clientDic.Remove(clientID);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//它是用于记录和服务器通信过的客户端的IP和端口
public class Client
{
public IPEndPoint clientAndpoint;
public string clinetStrID;
//上一次收到消息的时间
public long frontTime;
public Client(string ip ,int port)
{
//规则和外面一样 记录唯一ID 通过 ip+port 的形式拼接
clinetStrID = ip + port;
//就把客户端的信息记录下来了
clientAndpoint = new IPEndPoint(IPAddress.Parse(ip), port);
}

public void ReceiveMsg(byte[] bytes)
{
//为了避免处理消息时 又 接收到到了其他消息 所以这里先把数据拷贝出来
byte[] cacheBytes = new byte[512];
bytes.CopyTo(cacheBytes, 0);
//记录收到消息时间
frontTime = DateTime.Now.Ticks/TimeSpan.TicksPerSecond;
ThreadPool.QueueUserWorkItem(ReceiveHandle,cacheBytes);


}
//多线程处理消息
private void ReceiveHandle(object obj)
{
byte[] bytes = obj as byte[];
int nowIndex = 0;
//先处理消息
int msgID = BitConverter.ToInt32(bytes, nowIndex);
nowIndex += 4;
//在处理长度
int msgLength = BitConverter.ToInt32(bytes, nowIndex);
nowIndex += 4;
//在解析消息体

switch (msgID)
{
case 1001:
PlayerMsg playerMsg = new PlayerMsg();
playerMsg.Reading(bytes,nowIndex);
Console.WriteLine(playerMsg.playerID);
Console.WriteLine(playerMsg.playerData.name);
Console.WriteLine(playerMsg.playerData.atk);
Console.WriteLine(playerMsg.playerData.lev);
break;
case 1003:
//退出消息处理
break;
}
}
}

评论