├── .github
└── FUNDING.yml
├── .gitignore
├── .vs
└── SimpleUdp
│ └── v16
│ ├── .suo
│ └── Server
│ └── sqlite3
│ ├── db.lock
│ └── storage.ide
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── DONATIONS.md
├── LICENSE.md
├── README.md
├── assets
├── icon.ico
└── icon.png
└── src
├── Node
├── Node.csproj
└── Program.cs
├── SimpleUdp.sln
└── SimpleUdp
├── Common.cs
├── Datagram.cs
├── EndpointMetadata.cs
├── LICENSE.md
├── SimpleUdp.csproj
├── SimpleUdp.xml
├── UdpEndpoint.cs
└── assets
├── icon.ico
└── icon.png
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [jchristn]
2 | custom: ["https://paypal.me/joelchristner"]
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ###
2 | ###
3 | ### Node
4 | ###
5 | ###
6 |
7 | # Node modules:
8 | node_modules
9 | node_modules/
10 |
11 | ###
12 | ###
13 | ### JetBrains
14 | ###
15 | ###
16 |
17 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
18 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
19 |
20 | # User-specific stuff:
21 | .idea
22 | .idea/
23 | .idea/**/workspace.xml
24 | .idea/**/tasks.xml
25 | .idea/dictionaries
26 |
27 | # Sensitive or high-churn files:
28 | .idea/**/dataSources/
29 | .idea/**/dataSources.ids
30 | .idea/**/dataSources.xml
31 | .idea/**/dataSources.local.xml
32 | .idea/**/sqlDataSources.xml
33 | .idea/**/dynamic.xml
34 | .idea/**/uiDesigner.xml
35 |
36 | # Gradle:
37 | .idea/**/gradle.xml
38 | .idea/**/libraries
39 |
40 | # CMake
41 | cmake-build-debug/
42 | cmake-build-release/
43 |
44 | # Mongo Explorer plugin:
45 | .idea/**/mongoSettings.xml
46 |
47 | ## File-based project format:
48 | *.iws
49 |
50 | ## Plugin-specific files:
51 |
52 | # IntelliJ
53 | out/
54 |
55 | # mpeltonen/sbt-idea plugin
56 | .idea_modules/
57 |
58 | # JIRA plugin
59 | atlassian-ide-plugin.xml
60 |
61 | # Cursive Clojure plugin
62 | .idea/replstate.xml
63 |
64 | # Crashlytics plugin (for Android Studio and IntelliJ)
65 | com_crashlytics_export_strings.xml
66 | crashlytics.properties
67 | crashlytics-build.properties
68 | fabric.properties
69 |
70 | ###
71 | ###
72 | ### Visual Studio
73 | ###
74 | ###
75 |
76 | ## Ignore Visual Studio temporary files, build results, and
77 | ## files generated by popular Visual Studio add-ons.
78 |
79 | # User-specific files
80 | *.suo
81 | *.user
82 | *.userosscache
83 | *.sln.docstates
84 |
85 | # User-specific files (MonoDevelop/Xamarin Studio)
86 | *.userprefs
87 |
88 | # Build results
89 | [Dd]ebug/
90 | [Dd]ebugPublic/
91 | [Rr]elease/
92 | [Rr]eleases/
93 | x64/
94 | x86/
95 | bld/
96 | [Bb]in/
97 | [Oo]bj/
98 | [Ll]og/
99 |
100 | # Visual Studio 2015 cache/options directory
101 | .vs/
102 | # Uncomment if you have tasks that create the project's static files in wwwroot
103 | #wwwroot/
104 |
105 | # MSTest test Results
106 | [Tt]est[Rr]esult*/
107 | [Bb]uild[Ll]og.*
108 |
109 | # NUNIT
110 | *.VisualState.xml
111 | TestResult.xml
112 |
113 | # Build Results of an ATL Project
114 | [Dd]ebugPS/
115 | [Rr]eleasePS/
116 | dlldata.c
117 |
118 | # DNX
119 | project.lock.json
120 | project.fragment.lock.json
121 | artifacts/
122 |
123 | *_i.c
124 | *_p.c
125 | *_i.h
126 | *.ilk
127 | *.meta
128 | *.obj
129 | *.pch
130 | *.pdb
131 | *.pgc
132 | *.pgd
133 | *.rsp
134 | *.sbr
135 | *.tlb
136 | *.tli
137 | *.tlh
138 | *.tmp
139 | *.tmp_proj
140 | *.log
141 | *.vspscc
142 | *.vssscc
143 | .builds
144 | *.pidb
145 | *.svclog
146 | *.scc
147 |
148 | # Chutzpah Test files
149 | _Chutzpah*
150 |
151 | # Visual C++ cache files
152 | ipch/
153 | *.aps
154 | *.ncb
155 | *.opendb
156 | *.opensdf
157 | *.sdf
158 | *.cachefile
159 | *.VC.db
160 | *.VC.VC.opendb
161 |
162 | # Visual Studio profiler
163 | *.psess
164 | *.vsp
165 | *.vspx
166 | *.sap
167 |
168 | # TFS 2012 Local Workspace
169 | $tf/
170 |
171 | # Guidance Automation Toolkit
172 | *.gpState
173 |
174 | # ReSharper is a .NET coding add-in
175 | _ReSharper*/
176 | *.[Rr]e[Ss]harper
177 | *.DotSettings.user
178 |
179 | # JustCode is a .NET coding add-in
180 | .JustCode
181 |
182 | # TeamCity is a build add-in
183 | _TeamCity*
184 |
185 | # DotCover is a Code Coverage Tool
186 | *.dotCover
187 |
188 | # Visual Studio code coverage results
189 | *.coverage
190 | *.coveragexml
191 |
192 | # NCrunch
193 | _NCrunch_*
194 | .*crunch*.local.xml
195 | nCrunchTemp_*
196 |
197 | # MightyMoose
198 | *.mm.*
199 | AutoTest.Net/
200 |
201 | # Web workbench (sass)
202 | .sass-cache/
203 |
204 | # Installshield output folder
205 | [Ee]xpress/
206 |
207 | # DocProject is a documentation generator add-in
208 | DocProject/buildhelp/
209 | DocProject/Help/*.HxT
210 | DocProject/Help/*.HxC
211 | DocProject/Help/*.hhc
212 | DocProject/Help/*.hhk
213 | DocProject/Help/*.hhp
214 | DocProject/Help/Html2
215 | DocProject/Help/html
216 |
217 | # Click-Once directory
218 | publish/
219 |
220 | # Publish Web Output
221 | *.[Pp]ublish.xml
222 | *.azurePubxml
223 | # TODO: Comment the next line if you want to checkin your web deploy settings
224 | # but database connection strings (with potential passwords) will be unencrypted
225 | *.pubxml
226 | *.publishproj
227 |
228 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
229 | # checkin your Azure Web App publish settings, but sensitive information contained
230 | # in these scripts will be unencrypted
231 | PublishScripts/
232 |
233 | # NuGet Packages
234 | *.nupkg
235 | # The packages folder can be ignored because of Package Restore
236 | **/packages/*
237 | # except build/, which is used as an MSBuild target.
238 | !**/packages/build/
239 | # Uncomment if necessary however generally it will be regenerated when needed
240 | #!**/packages/repositories.config
241 | # NuGet v3's project.json files produces more ignoreable files
242 | *.nuget.props
243 | *.nuget.targets
244 |
245 | # Microsoft Azure Build Output
246 | csx/
247 | *.build.csdef
248 |
249 | # Microsoft Azure Emulator
250 | ecf/
251 | rcf/
252 |
253 | # Windows Store app package directories and files
254 | AppPackages/
255 | BundleArtifacts/
256 | Package.StoreAssociation.xml
257 | _pkginfo.txt
258 |
259 | # Visual Studio cache files
260 | # files ending in .cache can be ignored
261 | *.[Cc]ache
262 | # but keep track of directories ending in .cache
263 | !*.[Cc]ache/
264 |
265 | # Others
266 | ClientBin/
267 | ~$*
268 | *~
269 | *.dbmdl
270 | *.dbproj.schemaview
271 | *.jfm
272 | *.publishsettings
273 | node_modules/
274 | orleans.codegen.cs
275 |
276 | # Since there are multiple workflows, uncomment next line to ignore bower_components
277 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
278 | #bower_components/
279 |
280 | # RIA/Silverlight projects
281 | Generated_Code/
282 |
283 | # Backup & report files from converting an old project file
284 | # to a newer Visual Studio version. Backup files are not needed,
285 | # because we have git ;-)
286 | _UpgradeReport_Files/
287 | Backup*/
288 | UpgradeLog*.XML
289 | UpgradeLog*.htm
290 |
291 | # SQL Server files
292 | *.mdf
293 | *.ldf
294 |
295 | # Business Intelligence projects
296 | *.rdl.data
297 | *.bim.layout
298 | *.bim_*.settings
299 |
300 | # Microsoft Fakes
301 | FakesAssemblies/
302 |
303 | # GhostDoc plugin setting file
304 | *.GhostDoc.xml
305 |
306 | # Node.js Tools for Visual Studio
307 | .ntvs_analysis.dat
308 |
309 | # Visual Studio 6 build log
310 | *.plg
311 |
312 | # Visual Studio 6 workspace options file
313 | *.opt
314 |
315 | # Visual Studio LightSwitch build output
316 | **/*.HTMLClient/GeneratedArtifacts
317 | **/*.DesktopClient/GeneratedArtifacts
318 | **/*.DesktopClient/ModelManifest.xml
319 | **/*.Server/GeneratedArtifacts
320 | **/*.Server/ModelManifest.xml
321 | _Pvt_Extensions
322 |
323 | # Paket dependency manager
324 | .paket/paket.exe
325 | paket-files/
326 |
327 | # FAKE - F# Make
328 | .fake/
329 |
330 | # JetBrains Rider
331 | .idea/
332 | *.sln.iml
333 |
334 | # CodeRush
335 | .cr/
336 |
337 | # Python Tools for Visual Studio (PTVS)
338 | __pycache__/
339 | *.pyc
340 |
--------------------------------------------------------------------------------
/.vs/SimpleUdp/v16/.suo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jchristn/SimpleUdp/f38294479821c2c3b79e2cf7e07194a9069ef4af/.vs/SimpleUdp/v16/.suo
--------------------------------------------------------------------------------
/.vs/SimpleUdp/v16/Server/sqlite3/db.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jchristn/SimpleUdp/f38294479821c2c3b79e2cf7e07194a9069ef4af/.vs/SimpleUdp/v16/Server/sqlite3/db.lock
--------------------------------------------------------------------------------
/.vs/SimpleUdp/v16/Server/sqlite3/storage.ide:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jchristn/SimpleUdp/f38294479821c2c3b79e2cf7e07194a9069ef4af/.vs/SimpleUdp/v16/Server/sqlite3/storage.ide
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | ## Current Version
4 |
5 | v2.0.x
6 |
7 | - Retarget to .NET 8.0
8 | - Removal of `Start`, `Stop` APIs, and, the started event
9 | - Better multi-platform compatibility (Windows, Mac OSX, Ubuntu)
10 |
11 | ## Previous Versions
12 |
13 | v1.2.x
14 | - Support for broadcast endpoints (set IP to null), thank you @charleypeng
15 | - Resolve issue associated with rapid send operations, thank you @seatrix
16 |
17 | v1.1.x
18 |
19 | - ```Events.Started``` and ```Events.Stopped```
20 | - ```UdpEndpoint.Start``` and ```UdpEndpoint.Stop``` APIs
21 |
22 |
23 | v1.0.0
24 |
25 | - Initial release
26 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | - Using welcoming and inclusive language
12 | - Being respectful of differing viewpoints and experiences
13 | - Gracefully accepting constructive criticism
14 | - Focusing on what is best for the community
15 | - Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | - The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | - Trolling, insulting/derogatory comments, and personal or political attacks
21 | - Public or private harassment
22 | - Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | - Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
44 |
45 | For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq
46 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Thank you for your interest in contributing!
4 |
5 | The following is a set of guidelines for contributing to our project on Github. These are mostly guidelines, not rules.
6 |
7 | ## Code of Conduct
8 |
9 | This project and everyone participating in it is governed by the Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to project moderators.
10 |
11 | ## Pull Requests
12 |
13 | Please follow these guidelines when submitting pull requests (PRs):
14 |
15 | - PRs should be manageable in size to make it easy for us to validate and integrate
16 | - Each PR should be contained to a single fix or a single feature
17 | - Describe the motivation for the PR
18 | - Describe a methodology to test and validate, if appropriate
19 |
20 | Please ensure that the code in your PR follows a style similar to that of the project. If you find a material discrepancy between the style followed by the project and a de facto standard style given the project language and framework, please let us know so we can amend and make our code more maintainable.
21 |
22 | ## Asking Questions
23 |
24 | Prior to asking questions, please review closed issues and wiki pages. If your question is not answered in either of those places, please feel free to file an issue! This will also help us to build out documentation.
25 |
26 | ## Reporting Bugs
27 |
28 | If you encounter an issue, please let us know! We kindly ask that you supply the following information with your bug report when you file an issue. Feel free to copy/paste from the below and use as a template.
29 |
30 | --- Bug Report ---
31 |
32 | Operating system and version: Windows 10
33 | Framework and runtime: .NET Core 2.0
34 | Issue encountered: The widget shifted left
35 | Expected behavior: The widget should have shifted right
36 | Steps to reproduce: Instantiate the widget and call .ShiftRight()
37 | Sample code encapsulating the problem:
38 | ```
39 | Widget widget = new Widget();
40 | widget.ShiftRight();
41 | ```
42 | Exception details: [insert exception output here]
43 | Stack trace: [if appropriate]
44 |
45 | --- End ---
46 |
47 | ## Suggesting Enhancements
48 |
49 | Should there be a way that you feel we could improve upon this project, please feel free to file an issue and use the template below to provide the necessary details to support the request.
50 |
51 | Some basic guidelines for suggesting enhancements:
52 |
53 | - Use a clear and descriptive title for the issue to identify the suggestion.
54 | - Provide a step-by-step description of the suggested enhancement in as many details as possible.
55 | - Provide specific examples to demonstrate the steps including copy/pasteable snippets where possible
56 | - Describe the current behavior and the behavior you would like to see
57 | - Describe the usefulness of the enhancement to yourself and potentially to others
58 |
59 | --- Enhancement Request ---
60 |
61 | Enhancement request title: Widgets should have a color attribute
62 | Use case: I want to specify what color a widget is
63 | Current behavior: Widgets don't have a color
64 | Requested behavior: Allow me to specify a widget's color
65 | Recommended implementation: Add a Color attribute to the Widget class
66 | Usefulness of the enhancement: All widgets have color, and everyone has to build their own implementation to set this
67 |
68 | --- End ---
69 |
--------------------------------------------------------------------------------
/DONATIONS.md:
--------------------------------------------------------------------------------
1 | ## Donations
2 |
3 | If you're interested in financially supporting this work on other open source projects I manage, first of all, thank you! It brings me delight to know that this software has helped you in some way. Please find below address details for donations using
4 |
5 | ### Traditional
6 |
7 | | Method | Address |
8 | |--------|---------|
9 | | PayPal | @joelchristner - https://paypal.me/joelchristner?country.x=US&locale.x=en_US |
10 | | Venmo | @Joel-Christner - https://account.venmo.com/u/Joel-Christner |
11 |
12 | ### Cryptocurrency (Mainstream)
13 |
14 | | Method | Address |
15 | |----------|---------|
16 | | Bitcoin | 3HRgnvEWQBDdWDp75CFDsz3PirCYmftDwU |
17 | | Ethereum | 0xE064dC84270e17e2Ac34b2552461d672BdBC5e36 |
18 |
19 | ### Cryptocurrency (Altcoins)
20 |
21 | | Method | Address |
22 | |--------|---------|
23 | | XRP | Tag 1765608084 Address rw2ciyaNshpHe7bCHo4bRWq6pqqynnWKQg |
24 | | Shiba Inu SHIB | 0xdA58D4ba0d5823d80a0C42C69E139124B889c69a |
25 | | Algorand ALGO | FFKA23KC4BHEU5HM4OQHLEILVIYDLRXYK6WD6UI573JPUGHZR43JVHAF7A |
26 | | Stellar Lumens XML | Memo 2264929895 Address GDQP2KPQGKIHYJGXNUIYOMHARUARCA7DJT5FO2FFOOKY3B2WSQHG4W37 |
27 | | Dogecoin DOGE | DQ2dn4UifpYA8RyuNF1t112Y1XH5L42Rxv |
28 | | Cardano ADA | addr1vxrxyrv0phgr2xcl08dj0sfy425mhqehuu4dy99ja4nhtwqfsvgjk |
29 |
30 | If you have a coin you prefer to use, please let me know!
31 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # The MIT License (MIT)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # SimpleUdp
4 |
5 | ## Simple wrapper for UDP client and server in C#
6 |
7 | [](https://www.nuget.org/packages/SimpleUdp/) [](https://www.nuget.org/packages/SimpleUdp)
8 |
9 | SimpleUdp provides simple methods for creating your own UDP-based sockets application, enabling easy integration of sending data, receiving data, and building state machines.
10 |
11 | ## New in v2.0.x
12 |
13 | - Retarget to .NET 8.0
14 | - Removal of `Start`, `Stop` APIs, and, the started event
15 | - Better multi-platform compatibility (Windows, Mac OSX, Ubuntu)
16 |
17 | ## Help or Feedback
18 |
19 | Need help or have feedback? Please file an issue here!
20 |
21 | ## Special Thanks
22 |
23 | Thanks to community members that have helped improve this library! @jholzer @charleypeng @seatrix
24 |
25 | ## Need TCP Instead?
26 |
27 | I have you covered.
28 |
29 | - WatsonTcp - easiest way to build TCP-based applications with built-in framing
30 | - Github: https://github.com/jchristn/watsontcp
31 | - NuGet: https://www.nuget.org/packages/WatsonTcp/
32 | - [](https://www.nuget.org/packages/WatsonTcp/)
33 | - SimpleTcp - lightweight TCP wrapper without framing
34 | - Github: https://github.com/jchristn/simpletcp
35 | - NuGet: https://www.nuget.org/packages/SuperSimpleTcp/
36 | - [](https://www.nuget.org/packages/SuperSimpleTcp/)
37 | - CavemanTcp - TCP wrapper exposing controls for sending and receiving data to build state machines
38 | - Github: https://github.com/jchristn/cavemantcp
39 | - NuGet: https://www.nuget.org/packages/CavemanTcp/
40 | - [](https://www.nuget.org/packages/CavemanTcp/)
41 |
42 | Don't know what to use? Just ask! File an issue, I'll be happy to help.
43 |
44 | ## Simple Example
45 |
46 | Start a node.
47 | ```
48 | using SimpleUdp;
49 |
50 | UdpEndpoint udp = new UdpEndpoint("127.0.0.1", 8000);
51 | udp.EndpointDetected += EndpointDetected;
52 |
53 | // only if you want to receive messages...
54 | udp.DatagramReceived += DatagramReceived;
55 |
56 | // send a message...
57 | udp.Send("127.0.0.1", 8001, "Hello to my friend listening on port 8001!");
58 |
59 | static void EndpointDetected(object sender, EndpointMetadata md)
60 | {
61 | Console.WriteLine("Endpoint detected: " + md.Ip + ":" + md.Port);
62 | }
63 |
64 | static void DatagramReceived(object sender, Datagram dg)
65 | {
66 | Console.WriteLine("[" + dg.Ip + ":" + dg.Port + "]: " + Encoding.UTF8.GetString(dg.Data));
67 | }
68 | ```
69 |
70 | ## The Node Project
71 |
72 | Start node 1.
73 | ```
74 | Node\bin\Debug\netcoreapp3.1> node 127.0.0.1 8000
75 | ```
76 |
77 | Start node 2.
78 | ```
79 | Node\bin\Debug\netcoreapp3.1> node 127.0.0.1 8001
80 | ```
81 |
82 | Send message from node 1 to node 2. To do this, enter a command as follows:
83 | ```
84 | [ip:port] [msg]
85 | ```
86 | i.e.
87 | ```
88 | 127.0.0.1:8001 hello to my friend running on port 8001!
89 | ```
90 |
91 | ```
92 | [127.0.0.1:8000 Command/? for help]: 127.0.0.1:8001 hello to my friend on port 8001!
93 | ```
94 |
95 | Send message from node 2 to node 1.
96 | ```
97 | [127.0.0.1:8001 Command/? for help]: Endpoint detected: 127.0.0.1:8000
98 | [127.0.0.1:8000]: hello to my friend on port 8001!
99 | 127.0.0.1:8000 hello back to you my friend!
100 | ```
101 |
102 | ## Version History
103 |
104 | Please refer to CHANGELOG.md.
105 |
--------------------------------------------------------------------------------
/assets/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jchristn/SimpleUdp/f38294479821c2c3b79e2cf7e07194a9069ef4af/assets/icon.ico
--------------------------------------------------------------------------------
/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jchristn/SimpleUdp/f38294479821c2c3b79e2cf7e07194a9069ef4af/assets/icon.png
--------------------------------------------------------------------------------
/src/Node/Node.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net6.0;net7.0;net8.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/Node/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using SimpleUdp;
5 |
6 | namespace Node
7 | {
8 | class Program
9 | {
10 | static string _Ip = null;
11 | static int _Port = 0;
12 | static UdpEndpoint _UdpEndpoint;
13 |
14 | static void Main(string[] args)
15 | {
16 | if (args == null || args.Length < 2)
17 | {
18 | Usage();
19 | return;
20 | }
21 | /*
22 | *
23 | *
24 | * Usage:
25 | * node 127.0.0.1 8000
26 | *
27 | * Starts the endpoint on IP address 127.0.0.1 port 8000.
28 | *
29 | *
30 | *
31 | */
32 |
33 | _Ip = args[0];
34 | _Port = Convert.ToInt32(args[1]);
35 |
36 | _UdpEndpoint = new UdpEndpoint(_Ip, _Port);
37 | _UdpEndpoint.EndpointDetected += EndpointDetected;
38 | _UdpEndpoint.DatagramReceived += DatagramReceived;
39 | _UdpEndpoint.ServerStopped += NodeStopped;
40 |
41 | while (true)
42 | {
43 | Console.Write("[" + _Ip + ":" + _Port + " Command/? for help]: ");
44 | string userInput = Console.ReadLine();
45 | if (String.IsNullOrEmpty(userInput)) continue;
46 |
47 | if (userInput.Equals("?"))
48 | {
49 | Menu();
50 | }
51 | else if (userInput.Equals("q"))
52 | {
53 | break;
54 | }
55 | else if (userInput.Equals("cls"))
56 | {
57 | Console.Clear();
58 | }
59 | else if (userInput.Equals("list"))
60 | {
61 | List recents = _UdpEndpoint.Endpoints;
62 | if (recents != null)
63 | {
64 | Console.WriteLine("Recent endpoints");
65 | foreach (string endpoint in recents) Console.WriteLine(" " + endpoint);
66 | }
67 | else
68 | {
69 | Console.WriteLine("None");
70 | }
71 | }
72 | else
73 | {
74 | string[] parts = userInput.Split(new char[] { ' ' }, 2);
75 | if (parts.Length != 2) continue;
76 |
77 | string msg = parts[1];
78 | string ipPort = parts[0];
79 | int colonIndex = parts[0].LastIndexOf(':');
80 | string ip = ipPort.Substring(0, colonIndex);
81 | int port = Convert.ToInt32(ipPort.Substring(colonIndex + 1));
82 |
83 | _UdpEndpoint.Send(ip, port, msg);
84 | }
85 | }
86 |
87 | Console.ReadLine();
88 | }
89 |
90 | static void Usage()
91 | {
92 | Console.WriteLine("Usage:");
93 | Console.WriteLine("> node 127.0.0.1 8000");
94 | Console.WriteLine("Starts the endpoint on IP address 127.0.0.1 port 8000");
95 | }
96 |
97 | static void Menu()
98 | {
99 | Console.WriteLine("");
100 | Console.WriteLine("Available commands");
101 | Console.WriteLine(" q quit");
102 | Console.WriteLine(" ? help, this menu");
103 | Console.WriteLine(" cls clear the screen");
104 | Console.WriteLine(" list list recent endpoints");
105 | Console.WriteLine("");
106 | Console.WriteLine("To send a message, use the form 'ip:port message', i.e.");
107 | Console.WriteLine("127.0.0.1:8001 hello world!");
108 | Console.WriteLine("");
109 | }
110 |
111 | static void EndpointDetected(object sender, EndpointMetadata md)
112 | {
113 | Console.WriteLine("Endpoint detected: " + md.Ip + ":" + md.Port);
114 | }
115 |
116 | static void DatagramReceived(object sender, Datagram dg)
117 | {
118 | Console.WriteLine("[" + dg.Ip + ":" + dg.Port + "]: " + Encoding.UTF8.GetString(dg.Data));
119 | }
120 |
121 | private static void NodeStarted(object sender, EventArgs e)
122 | {
123 | Console.WriteLine("*** Node started");
124 | }
125 |
126 | private static void NodeStopped(object sender, EventArgs e)
127 | {
128 | Console.WriteLine("*** Node stopped");
129 | }
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/src/SimpleUdp.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29411.108
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleUdp", "SimpleUdp\SimpleUdp.csproj", "{13B36B6B-6B6A-430E-A631-B75A8C87AB22}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Node", "Node\Node.csproj", "{C75CD2A7-FCBB-48A5-B0FC-98A06CA8B6CB}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {13B36B6B-6B6A-430E-A631-B75A8C87AB22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {13B36B6B-6B6A-430E-A631-B75A8C87AB22}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {13B36B6B-6B6A-430E-A631-B75A8C87AB22}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {13B36B6B-6B6A-430E-A631-B75A8C87AB22}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {C75CD2A7-FCBB-48A5-B0FC-98A06CA8B6CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {C75CD2A7-FCBB-48A5-B0FC-98A06CA8B6CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {C75CD2A7-FCBB-48A5-B0FC-98A06CA8B6CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {C75CD2A7-FCBB-48A5-B0FC-98A06CA8B6CB}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {5A2BCD14-57CA-4605-B694-66332F0B910A}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/src/SimpleUdp/Common.cs:
--------------------------------------------------------------------------------
1 | namespace SimpleUdp
2 | {
3 | using System;
4 |
5 | ///
6 | /// Commonly used static methods for SimpleUdp.
7 | ///
8 | public static class Common
9 | {
10 | ///
11 | /// Parse an IP:port string to its parts.
12 | ///
13 | /// IP:port.
14 | /// IP address.
15 | /// Port number.
16 | public static void ParseIpPort(string ipPort, out string ip, out int port)
17 | {
18 | if (String.IsNullOrEmpty(ipPort)) throw new ArgumentNullException(nameof(ipPort));
19 |
20 | ip = null;
21 | port = -1;
22 |
23 | int colonIndex = ipPort.LastIndexOf(':');
24 | if (colonIndex != -1)
25 | {
26 | ip = ipPort.Substring(0, colonIndex);
27 | port = Convert.ToInt32(ipPort.Substring(colonIndex + 1));
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/SimpleUdp/Datagram.cs:
--------------------------------------------------------------------------------
1 | namespace SimpleUdp
2 | {
3 | using System;
4 |
5 | ///
6 | /// Datagram received by this endpoint.
7 | ///
8 | public class Datagram
9 | {
10 | #region Public-Members
11 |
12 | ///
13 | /// IP address of the remote endpoint.
14 | ///
15 | public string Ip
16 | {
17 | get
18 | {
19 | return _Ip;
20 | }
21 | set
22 | {
23 | if (String.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(Ip));
24 | _Ip = value;
25 | }
26 | }
27 |
28 | ///
29 | /// Port number of the remote endpoint.
30 | ///
31 | public int Port
32 | {
33 | get
34 | {
35 | return _Port;
36 | }
37 | set
38 | {
39 | if (value < 0 || value > 65535) throw new ArgumentOutOfRangeException(nameof(Port));
40 | _Port = value;
41 | }
42 | }
43 |
44 | ///
45 | /// Data received from the remote endpoint.
46 | ///
47 | public byte[] Data
48 | {
49 | get
50 | {
51 | return _Data;
52 | }
53 | set
54 | {
55 | if (value == null) value = Array.Empty();
56 | _Data = value;
57 | }
58 | }
59 |
60 | #endregion
61 |
62 | #region Private-Members
63 |
64 | private string _Ip = "127.0.0.1";
65 | private int _Port = 0;
66 | private byte[] _Data = Array.Empty();
67 |
68 | #endregion
69 |
70 | #region Constructors-and-Factories
71 |
72 | ///
73 | /// Instantiate.
74 | ///
75 | public Datagram()
76 | {
77 |
78 | }
79 |
80 | ///
81 | /// Instantiate.
82 | ///
83 | /// IP address of the remote endpoint.
84 | /// Port of the remote endpoint.
85 | /// Data.
86 | internal Datagram(string ip, int port, byte[] data)
87 | {
88 | Ip = ip;
89 | Port = port;
90 | Data = data;
91 | }
92 |
93 | #endregion
94 |
95 | #region Public-Methods
96 |
97 | #endregion
98 |
99 | #region Private-Methods
100 |
101 | #endregion
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/SimpleUdp/EndpointMetadata.cs:
--------------------------------------------------------------------------------
1 | namespace SimpleUdp
2 | {
3 | using System;
4 |
5 | ///
6 | /// Remote endpoint metadata.
7 | ///
8 | public class EndpointMetadata
9 | {
10 | #region Public-Members
11 |
12 | ///
13 | /// IP address of the remote endpoint.
14 | ///
15 | public string Ip
16 | {
17 | get
18 | {
19 | return _Ip;
20 | }
21 | set
22 | {
23 | if (String.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(Ip));
24 | _Ip = value;
25 | }
26 | }
27 |
28 | ///
29 | /// Port number of the remote endpoint.
30 | ///
31 | public int Port
32 | {
33 | get
34 | {
35 | return _Port;
36 | }
37 | set
38 | {
39 | if (value < 0 || value > 65535) throw new ArgumentOutOfRangeException(nameof(Port));
40 | _Port = value;
41 | }
42 | }
43 |
44 | #endregion
45 |
46 | #region Private-Members
47 |
48 | private string _Ip = "127.0.0.1";
49 | private int _Port = 0;
50 |
51 | #endregion
52 |
53 | #region Constructors-and-Factories
54 |
55 | ///
56 | /// Instantiate.
57 | ///
58 | public EndpointMetadata()
59 | {
60 |
61 | }
62 |
63 | ///
64 | /// Instantiate.
65 | ///
66 | /// IP address of the remote endpoint.
67 | /// Port of the remote endpoint.
68 | internal EndpointMetadata(string ip, int port)
69 | {
70 | Ip = ip;
71 | Port = port;
72 | }
73 |
74 | #endregion
75 |
76 | #region Public-Methods
77 |
78 | #endregion
79 |
80 | #region Private-Methods
81 |
82 | #endregion
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/SimpleUdp/LICENSE.md:
--------------------------------------------------------------------------------
1 | # The MIT License (MIT)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/src/SimpleUdp/SimpleUdp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1;net6.0;net7.0;net8.0
5 | 2.0.2
6 | Library
7 | assets\icon.ico
8 |
9 | Joel Christner
10 | SimpleUdp is a super simple way of building UDP clients and servers in C#.
11 | (c)2024 Joel Christner
12 | LICENSE.md
13 | https://github.com/jchristn/SimpleUdp
14 | https://github.com/jchristn/SimpleUdp
15 | Github
16 | udp messaging socket message sockets api rpc datagram
17 | Breaking changes to accommodate multi-platform
18 | true
19 | https://raw.githubusercontent.com/jchristn/SimpleUdp/master/assets/icon.ico
20 | icon.png
21 | README.md
22 |
23 |
24 |
25 | SimpleUdp.xml
26 |
27 |
28 |
29 |
30 | True
31 | \
32 |
33 |
34 | True
35 | \
36 |
37 |
38 | True
39 |
40 | Always
41 |
42 |
43 |
44 | True
45 | \
46 | Always
47 |
48 |
49 | True
50 | \
51 | Always
52 |
53 |
54 | Always
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/src/SimpleUdp/SimpleUdp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | SimpleUdp
5 |
6 |
7 |
8 |
9 | Commonly used static methods for SimpleUdp.
10 |
11 |
12 |
13 |
14 | Parse an IP:port string to its parts.
15 |
16 | IP:port.
17 | IP address.
18 | Port number.
19 |
20 |
21 |
22 | Datagram received by this endpoint.
23 |
24 |
25 |
26 |
27 | IP address of the remote endpoint.
28 |
29 |
30 |
31 |
32 | Port number of the remote endpoint.
33 |
34 |
35 |
36 |
37 | Data received from the remote endpoint.
38 |
39 |
40 |
41 |
42 | Instantiate.
43 |
44 |
45 |
46 |
47 | Instantiate.
48 |
49 | IP address of the remote endpoint.
50 | Port of the remote endpoint.
51 | Data.
52 |
53 |
54 |
55 | Remote endpoint metadata.
56 |
57 |
58 |
59 |
60 | IP address of the remote endpoint.
61 |
62 |
63 |
64 |
65 | Port number of the remote endpoint.
66 |
67 |
68 |
69 |
70 | Instantiate.
71 |
72 |
73 |
74 |
75 | Instantiate.
76 |
77 | IP address of the remote endpoint.
78 | Port of the remote endpoint.
79 |
80 |
81 |
82 | UDP endpoint, both client and server.
83 |
84 |
85 |
86 |
87 | Event to fire when a new endpoint is detected.
88 |
89 |
90 |
91 |
92 | Event to fire when a datagram is received.
93 |
94 |
95 |
96 |
97 | Event to fire when the server is stopped.
98 |
99 |
100 |
101 |
102 | Retrieve a list of (up to) the 100 most recently seen endpoints.
103 |
104 |
105 |
106 |
107 | Maximum datagram size, must be greater than zero and less than or equal to 65507.
108 |
109 |
110 |
111 |
112 | Instantiate the UDP endpoint.
113 | If you wish to also receive datagrams, set the 'DatagramReceived' event and call 'StartServer()'.
114 |
115 | IP address on which to listen.
116 | Port number on which to listen.
117 |
118 |
119 |
120 | Dispose.
121 |
122 |
123 |
124 |
125 | Dispose.
126 |
127 | Disposing.
128 |
129 |
130 |
131 | Send a datagram to the specific IP address and UDP port.
132 | This will throw a SocketException if the report UDP port is unreachable.
133 |
134 | IP address.
135 | Port.
136 | Text to send.
137 | Time to live, the maximum number of routers the packet is allowed to traverse. Minimum is 0, default is 64.
138 |
139 |
140 |
141 | Send a datagram to the specific IP address and UDP port.
142 | This will throw a SocketException if the report UDP port is unreachable.
143 |
144 | IP address.
145 | Port.
146 | Bytes.
147 | Time to live, the maximum number of routers the packet is allowed to traverse. Minimum is 0, default is 64.
148 |
149 |
150 |
151 | Send a datagram asynchronously to the specific IP address and UDP port.
152 | This will throw a SocketException if the report UDP port is unreachable.
153 |
154 | IP address.
155 | Port.
156 | Text to send.
157 | Time to live, the maximum number of routers the packet is allowed to traverse. Minimum is 0, default is 64.
158 |
159 |
160 |
161 | Send a datagram asynchronously to the specific IP address and UDP port.
162 | This will throw a SocketException if the report UDP port is unreachable.
163 |
164 | IP address.
165 | Port.
166 | Bytes.
167 | Time to live, the maximum number of routers the packet is allowed to traverse. Minimum is 0, default is 64.
168 |
169 |
170 |
171 |
--------------------------------------------------------------------------------
/src/SimpleUdp/UdpEndpoint.cs:
--------------------------------------------------------------------------------
1 | namespace SimpleUdp
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Net;
6 | using System.Net.Sockets;
7 | using System.Text;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using Caching;
11 |
12 | ///
13 | /// UDP endpoint, both client and server.
14 | ///
15 | public class UdpEndpoint : IDisposable
16 | {
17 | #region Public-Members
18 |
19 | ///
20 | /// Event to fire when a new endpoint is detected.
21 | ///
22 | public event EventHandler EndpointDetected;
23 |
24 | ///
25 | /// Event to fire when a datagram is received.
26 | ///
27 | public event EventHandler DatagramReceived;
28 |
29 | ///
30 | /// Event to fire when the server is stopped.
31 | ///
32 | public event EventHandler ServerStopped;
33 |
34 | ///
35 | /// Retrieve a list of (up to) the 100 most recently seen endpoints.
36 | ///
37 | public List Endpoints
38 | {
39 | get
40 | {
41 | return _RemoteSockets.GetKeys();
42 | }
43 | }
44 |
45 | ///
46 | /// Maximum datagram size, must be greater than zero and less than or equal to 65507.
47 | ///
48 | public int MaxDatagramSize
49 | {
50 | get
51 | {
52 | return _MaxDatagramSize;
53 | }
54 | set
55 | {
56 | if (value < 1 || value > 65507) throw new ArgumentException("MaxDatagramSize must be greater than zero and less than or equal to 65507.");
57 | _MaxDatagramSize = value;
58 | }
59 | }
60 |
61 | #endregion
62 |
63 | #region Private-Members
64 |
65 | private bool _Disposed = false;
66 | private string _Ip = null;
67 | private int _Port = 0;
68 | private IPAddress _IPAddress;
69 | private Socket _Socket = null;
70 | private int _MaxDatagramSize = 65507;
71 | private EndPoint _Endpoint = new IPEndPoint(IPAddress.Any, 0);
72 | private UdpClient _UdpClient = null;
73 | private AsyncCallback _ReceiveCallback = null;
74 |
75 | private LRUCache _RemoteSockets = new LRUCache(100, 1);
76 |
77 | private SemaphoreSlim _SendLock = new SemaphoreSlim(1, 1);
78 |
79 | #endregion
80 |
81 | #region Internal-Classes
82 |
83 | internal class State
84 | {
85 | internal State(int bufferSize)
86 | {
87 | Buffer = new byte[bufferSize];
88 | }
89 |
90 | internal byte[] Buffer = null;
91 | }
92 |
93 | #endregion
94 |
95 | #region Constructors-and-Factories
96 |
97 | ///
98 | /// Instantiate the UDP endpoint.
99 | /// If you wish to also receive datagrams, set the 'DatagramReceived' event and call 'StartServer()'.
100 | ///
101 | /// IP address on which to listen.
102 | /// Port number on which to listen.
103 | public UdpEndpoint(string ip, int port)
104 | {
105 | if (port < 0 || port > 65535) throw new ArgumentException("Port must be greater than or equal to zero and less than or equal to 65535.");
106 | _Ip = ip;
107 | _Port = port;
108 |
109 | if (String.IsNullOrEmpty(ip)) _IPAddress = IPAddress.Any;
110 | else _IPAddress = IPAddress.Parse(ip);
111 |
112 | _UdpClient = new UdpClient();
113 | _UdpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
114 | _UdpClient.ExclusiveAddressUse = false;
115 |
116 | State state = new State(_MaxDatagramSize);
117 |
118 | _Socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
119 | _Socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.ReuseAddress, true);
120 | _Socket.Bind(new IPEndPoint(_IPAddress, _Port));
121 |
122 | _Socket.BeginReceiveFrom(state.Buffer, 0, _MaxDatagramSize, SocketFlags.None, ref _Endpoint, _ReceiveCallback = (ar) =>
123 | {
124 | try
125 | {
126 | State so = (State)ar.AsyncState;
127 | int bytes = _Socket.EndReceiveFrom(ar, ref _Endpoint);
128 |
129 | string senderIpPort = _Endpoint.ToString();
130 | string senderIp = null;
131 | int senderPort = 0;
132 | Common.ParseIpPort(senderIpPort, out senderIp, out senderPort);
133 |
134 | if (!_RemoteSockets.Contains(senderIpPort))
135 | {
136 | _RemoteSockets.AddReplace(senderIpPort, _Socket);
137 | EndpointDetected?.Invoke(this, new EndpointMetadata(senderIp, senderPort));
138 | }
139 |
140 | if (bytes == so.Buffer.Length)
141 | {
142 | DatagramReceived?.Invoke(this, new Datagram(senderIp, senderPort, so.Buffer));
143 | }
144 | else
145 | {
146 | byte[] buffer = new byte[bytes];
147 | Buffer.BlockCopy(so.Buffer, 0, buffer, 0, bytes);
148 | DatagramReceived?.Invoke(this, new Datagram(senderIp, senderPort, buffer));
149 | }
150 |
151 | _Socket.BeginReceiveFrom(so.Buffer, 0, _MaxDatagramSize, SocketFlags.None, ref _Endpoint, _ReceiveCallback, so);
152 | }
153 | catch (Exception)
154 | {
155 | ServerStopped?.Invoke(this, EventArgs.Empty);
156 | }
157 | }, state);
158 | }
159 |
160 | #endregion
161 |
162 | #region Public-Methods
163 |
164 | ///
165 | /// Dispose.
166 | ///
167 | public void Dispose()
168 | {
169 | Dispose(true);
170 | GC.SuppressFinalize(this);
171 | }
172 |
173 | ///
174 | /// Dispose.
175 | ///
176 | /// Disposing.
177 | protected virtual void Dispose(bool disposing)
178 | {
179 | if (_Disposed) return;
180 |
181 | if (disposing)
182 | {
183 | _UdpClient?.Dispose();
184 |
185 | if (_Socket != null)
186 | {
187 | _Socket.Close();
188 | }
189 | }
190 |
191 | _Disposed = true;
192 | }
193 |
194 | ///
195 | /// Send a datagram to the specific IP address and UDP port.
196 | /// This will throw a SocketException if the report UDP port is unreachable.
197 | ///
198 | /// IP address.
199 | /// Port.
200 | /// Text to send.
201 | /// Time to live, the maximum number of routers the packet is allowed to traverse. Minimum is 0, default is 64.
202 | public void Send(string ip, int port, string text, short ttl = 64)
203 | {
204 | if (String.IsNullOrEmpty(ip)) throw new ArgumentNullException(nameof(ip));
205 | if (port < 0 || port > 65535) throw new ArgumentException("Port is out of range; must be greater than or equal to zero and less than or equal to 65535.");
206 | if (String.IsNullOrEmpty(text)) throw new ArgumentNullException(nameof(text));
207 | if (ttl < 0) throw new ArgumentOutOfRangeException(nameof(ttl));
208 | byte[] data = Encoding.UTF8.GetBytes(text);
209 | if (data.Length > _MaxDatagramSize) throw new ArgumentException("Data exceed maximum datagram size (" + data.Length + " data bytes, " + _MaxDatagramSize + " bytes).");
210 | SendInternal(ip, port, data, ttl);
211 | }
212 |
213 | ///
214 | /// Send a datagram to the specific IP address and UDP port.
215 | /// This will throw a SocketException if the report UDP port is unreachable.
216 | ///
217 | /// IP address.
218 | /// Port.
219 | /// Bytes.
220 | /// Time to live, the maximum number of routers the packet is allowed to traverse. Minimum is 0, default is 64.
221 | public void Send(string ip, int port, byte[] data, short ttl = 64)
222 | {
223 | if (String.IsNullOrEmpty(ip)) throw new ArgumentNullException(nameof(ip));
224 | if (port < 0 || port > 65535) throw new ArgumentException("Port is out of range; must be greater than or equal to zero and less than or equal to 65535.");
225 | if (data == null || data.Length < 1) throw new ArgumentNullException(nameof(data));
226 | if (data.Length > _MaxDatagramSize) throw new ArgumentException("Data exceed maximum datagram size (" + data.Length + " data bytes, " + _MaxDatagramSize + " bytes).");
227 | if (ttl < 0) throw new ArgumentOutOfRangeException(nameof(ttl));
228 | SendInternal(ip, port, data, ttl);
229 | }
230 |
231 | ///
232 | /// Send a datagram asynchronously to the specific IP address and UDP port.
233 | /// This will throw a SocketException if the report UDP port is unreachable.
234 | ///
235 | /// IP address.
236 | /// Port.
237 | /// Text to send.
238 | /// Time to live, the maximum number of routers the packet is allowed to traverse. Minimum is 0, default is 64.
239 | public async Task SendAsync(string ip, int port, string text, short ttl = 64)
240 | {
241 | if (String.IsNullOrEmpty(ip)) throw new ArgumentNullException(nameof(ip));
242 | if (port < 0 || port > 65535) throw new ArgumentException("Port is out of range; must be greater than or equal to zero and less than or equal to 65535.");
243 | if (String.IsNullOrEmpty(text)) throw new ArgumentNullException(nameof(text));
244 | byte[] data = Encoding.UTF8.GetBytes(text);
245 | if (data.Length > _MaxDatagramSize) throw new ArgumentException("Data exceed maximum datagram size (" + data.Length + " data bytes, " + _MaxDatagramSize + " bytes).");
246 | if (ttl < 0) throw new ArgumentOutOfRangeException(nameof(ttl));
247 | await SendInternalAsync(ip, port, data, ttl).ConfigureAwait(false);
248 | }
249 |
250 | ///
251 | /// Send a datagram asynchronously to the specific IP address and UDP port.
252 | /// This will throw a SocketException if the report UDP port is unreachable.
253 | ///
254 | /// IP address.
255 | /// Port.
256 | /// Bytes.
257 | /// Time to live, the maximum number of routers the packet is allowed to traverse. Minimum is 0, default is 64.
258 | public async Task SendAsync(string ip, int port, byte[] data, short ttl = 64)
259 | {
260 | if (String.IsNullOrEmpty(ip)) throw new ArgumentNullException(nameof(ip));
261 | if (port < 0 || port > 65535) throw new ArgumentException("Port is out of range; must be greater than or equal to zero and less than or equal to 65535.");
262 | if (data == null || data.Length < 1) throw new ArgumentNullException(nameof(data));
263 | if (data.Length > _MaxDatagramSize) throw new ArgumentException("Data exceed maximum datagram size (" + data.Length + " data bytes, " + _MaxDatagramSize + " bytes).");
264 | if (ttl < 0) throw new ArgumentOutOfRangeException(nameof(ttl));
265 | await SendInternalAsync(ip, port, data, ttl).ConfigureAwait(false);
266 | }
267 |
268 | #endregion
269 |
270 | #region Private-Methods
271 |
272 | private void SendInternal(string ip, int port, byte[] data, short ttl)
273 | {
274 | _SendLock.Wait();
275 |
276 | IPEndPoint ipe = new IPEndPoint(IPAddress.Parse(ip), port);
277 |
278 | try
279 | {
280 | _UdpClient.Ttl = ttl;
281 | _UdpClient.Send(data, data.Length, ipe);
282 | }
283 | finally
284 | {
285 | _SendLock.Release();
286 | }
287 | }
288 |
289 | private async Task SendInternalAsync(string ip, int port, byte[] data, short ttl)
290 | {
291 | await _SendLock.WaitAsync();
292 |
293 | IPEndPoint ipe = new IPEndPoint(IPAddress.Parse(ip), port);
294 |
295 | try
296 | {
297 | _UdpClient.Ttl = ttl;
298 | await _UdpClient.SendAsync(data, data.Length, ipe).ConfigureAwait(false);
299 | }
300 | catch (TaskCanceledException)
301 | {
302 |
303 | }
304 | catch (OperationCanceledException)
305 | {
306 |
307 | }
308 | finally
309 | {
310 | _SendLock.Release();
311 | }
312 | }
313 |
314 | #endregion
315 | }
316 | }
317 |
--------------------------------------------------------------------------------
/src/SimpleUdp/assets/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jchristn/SimpleUdp/f38294479821c2c3b79e2cf7e07194a9069ef4af/src/SimpleUdp/assets/icon.ico
--------------------------------------------------------------------------------
/src/SimpleUdp/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jchristn/SimpleUdp/f38294479821c2c3b79e2cf7e07194a9069ef4af/src/SimpleUdp/assets/icon.png
--------------------------------------------------------------------------------