Nimでオンラインゲーム用UDPサーバーの雛形を作る

最近RustやらPythonやらKotlinを触っています。
でも今回はNimでUDP通信（オンラインゲームサーバーっぽい）を試してみようというものです。
RustはMozzilaが推してるので情報が充実してきてるのですが、
いかんせんNimは…（泣）

なぜ今回Nimを選んだかというと、ズバリ処理速度です。
下記の記事を読んで、Nimダントツじゃん！となった次第です。

参考：http://h-miyako.hatenablog.com/entry/2015/01/23/060000

ちなみに環境はMacBook Pro (Mojave)で行いました。
MacでのNimの環境構築はこれだけ。

```
$ brew install nim
```

プロジェクトを作成するには以下

```
$ mkdir <プロジェクト名>
$ cd <プロジェクト名>
$ nimble init
```
一通りプロジェクト設定の質問に答えていくと
<プロジェクト名>.nimbleというファイルと、
srcフォルダが出来上がってると思います。
srcフォルダ配下には<プロジェクト名>.nimというファイルがあるので
ここに以下のサーバーの雛形を追加してみます。

```nim:server.nim
import net 
 
when isMainModule:
  var socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
  socket.bindAddr(Port(27960))
  echo "server bound to port 27960"
 
  while true:
    var 
      data = ""
      address = ""
      length = 64
      port: Port
 
    discard socket.recvFrom(data, length, address, port)
    echo address, " send ", data, " by ", $port<br>
```
こちらが記述できたら、以下でビルドします。
あ、Nimはインデントは2スペースなので要注意です。

```
$ nimble build
```
そうすると<プロジェクト名>のファイルがビルドされるので、
あとは実行！

```
$ ./<プロジェクト名>
```
これでサーバーが起動してechoで表示させていた「server bound to port 27960」の
メッセージが表示されるはずです。

では実際にUDPで叩いてみましょう。
クライアントはぶっちゃけPythonでもなんでもいいんですが、
せっかくなのでNimのソースコードを置いておきます。
先程の手順と同様にプロジェクト作って実行してください。

```nim:client.nim
import net 
 
when isMainModule:
  var socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
  socket.bindAddr(Port(27961))
  socket.sendTo("127.0.0.1", Port(27960), "Hello!")
 
  while true:
    var 
      data = ""
      address = ""
      length = 64
      port: Port
 
    discard socket.recvFrom(data, length, address, port)
    echo address, " send ", data, " by ", $port
```
Clientが27961ポート、サーバーが27960ポートを使用して通信します。
上手く実行できればサーバー側に「192.168.0.1 send  Hello!  by  27961」のように
表示されるはずです。
意外とnetライブラリの情報がなかったのでドキュメントみて頑張るしかなかった。。

さらにオンラインゲームだとユーザーの情報や、アイテムの情報など
データのフォーマットがあったほうがわかりやすいかと思いますので、
Jsonの受け渡し処理をそれぞれ追加したものを載せて、今回はここまでにしたいと思います。
Nimの普及を願って…！

```nim:server.nim
import net 
import json
 
when isMainModule:
  var socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
  socket.bindAddr(Port(27960))
  echo "server bound to port 27960"
 
  while true:
    var 
      data = ""                                                                                                                                                                                            
      address = ""
      length = 64
      port: Port
 
    discard socket.recvFrom(data, length, address, port)
    echo address, " send ", data, " by ", $port
    var jsonStr = parseJson(data)
    echo $jsonStr["key1"]
```

```nim:client.nim
import net 
import json
 
when isMainModule:
  var socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
  socket.bindAddr(Port(27961))
  let jsonObj = %* { "key1": "value1", "key2": 1 } 
  socket.sendTo("127.0.0.1", Port(27960), $jsonObj)
 
  while true:
    var 
      data = ""
      address = ""                                                                                                                                                                                         
      length = 64
      port: Port
 
    discard socket.recvFrom(data, length, address, port)
    echo address, " send ", data, " by ", $port
```