-
Notifications
You must be signed in to change notification settings - Fork 0
/
UdpModule.cs
161 lines (141 loc) · 5.03 KB
/
UdpModule.cs
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
/// <summary>
/// UDP 통신 모듈
/// </summary>
public class UdpModule
{
/// <summary>
/// UDP를 통해 전달받을 데이터 형식
/// </summary>
public class ReceiveData
{
public string header;
public byte[] content;
public ReceiveData(string header, byte[] content)
{
this.header = header;
this.content = content;
}
}
public delegate void ReceiveMessageHandler(ReceiveData message);
/// <summary>
/// UDP를 통해 전달받은 데이터를 처리한 이벤트
/// </summary>
/// <usage>
/// udp.OnReceiveMessage += ShowLog;
///
/// private void ShowLog(UdpModule.ReceiveData message)
/// {
/// Console.WriteLine($"{message.header} : {Encoding.Default.GetString(message.content)}");
/// }
/// </usage>
public event ReceiveMessageHandler OnReceiveMessage;
public delegate void LogEventHandler(string message);
public event LogEventHandler Log;
private UdpClient udpClient;
private Thread receiveThread;
private Thread invokeMessageThread;
private Queue<ReceiveData> receiveDataQueue;
private readonly int udpConnectionReset = -1744830452;
private readonly int headerSize = 10;
private string broadcastIP;
/// <summary>
/// UDP 모듈을 초기화시켜준다.
/// </summary>
/// <param name="broadcastIP">Broadcast로 보낼 IP</param>
/// <param name="port">열어놓을 포트</param>
/// <usage>
/// UdpModule udp = new UdpModule();
/// udp.Initialize(broadcastIP, udpServerPort);
/// </usage>
public void Initialize(string broadcastIP, int port)
{
this.broadcastIP = broadcastIP;
IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Any, port);
udpClient = new UdpClient(iPEndPoint)
{
EnableBroadcast = true
};
receiveDataQueue = new Queue<ReceiveData>();
receiveThread = new Thread(ReceiveMessage);
receiveThread.Start();
invokeMessageThread = new Thread(InvokeMessageEvent);
invokeMessageThread.Start();
// UDP가 ICMP 메세지를 받아 수신을 정지하는 것을 막기 위한 장치 (Exception을 무시한다)
// udpClient.Client.IOControl(udpConnectionReset, new byte[] { 0, 0, 0, 0 }, null);
}
/// <summary>
/// UDP 모듈을 통해 데이터를 전달한다.
/// </summary>
/// <param name="header">전달할 데이터의 헤더, 크기는 10 Byte까지다.</param>
/// <param name="contentsData">전달할 데이터</param>
/// <param name="targetPort">전달할 대상의 포트</param>
/// <param name="targetIP">전달할 대상의 IP, 공백일 경우 Broadcast로 보낸다.</param>
/// <usage>
/// udp.SendMessage("Command", datas, 8080, "192.168.0.100");
/// </usage>
public void SendMessage(string header, byte[] contentsData, int targetPort, string targetIP = null)
{
byte[] headerData = Encoding.UTF8.GetBytes(header);
Array.Resize(ref headerData, headerSize);
byte[] sendData = new byte[headerData.Length + contentsData.Length];
Array.Copy(headerData, sendData, headerData.Length);
Array.Copy(contentsData, 0, sendData, headerData.Length, contentsData.Length);
if(targetIP == null)
{
targetIP = broadcastIP;
}
udpClient.Send(sendData, sendData.Length, targetIP, targetPort);
}
public void Terminate()
{
receiveThread?.Abort();
invokeMessageThread?.Abort();
udpClient.Close();
}
private void ReceiveMessage()
{
try
{
IPEndPoint senderEndPoint = new IPEndPoint(IPAddress.Any, 0);
while(true)
{
byte[] receivedData = udpClient.Receive(ref senderEndPoint);
byte[] headerData = new byte[headerSize];
byte[] contentsData = new byte[receivedData.Length - headerData.Length];
Array.Copy(receivedData, headerData, headerData.Length);
headerData = Array.FindAll(headerData, o => o != 0);
Array.Copy(receivedData, headerSize, contentsData, 0, contentsData.Length);
ReceiveData receiveData = new ReceiveData(Encoding.Default.GetString(headerData), contentsData);
receiveDataQueue.Enqueue(receiveData);
}
}
catch(ThreadInterruptedException e)
{
Log?.Invoke(e.Message);
}
}
private void InvokeMessageEvent()
{
try
{
while(true)
{
if(receiveDataQueue.Count > 0)
{
ReceiveData data = receiveDataQueue.Dequeue();
OnReceiveMessage?.Invoke(data);
}
}
}
catch(ThreadInterruptedException e)
{
Log?.Invoke(e.Message);
}
}
}