LoginSignup
0

More than 3 years have passed since last update.

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

Posted at

最近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というファイルがあるので
ここに以下のサーバーの雛形を追加してみます。

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のソースコードを置いておきます。
先程の手順と同様にプロジェクト作って実行してください。

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の普及を願って…!

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"]
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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0