Tutorial:Networking with UDP-TheServer (日本語)

UDP サーバー用の完全なソースです。

local socket = require "socket"

-- 開始
local udp = socket.udp()

-- 通常はデータを保有するか、一定量の時間が経過するまで
-- 読み取りは阻止されます。
-- それは目的に適合していませんので、
-- 'timeout' へ 0 を設定して読み取り阻止を解除します。
udp:settimeout(0)

-- クライアントとは異なり、サーバーは、その'範囲'の場所、
-- または粗悪なクライアントに関して特定する必要があります。
-- 従って、望むもの全てに対して幸いにも自動的に割り当ることができますが、
-- その地のものを割り当てるようにサーバーに対して命じる必要があります。
-- 
-- 最初の部分は、どの"インタフェース"へ割り当てるべきかであり…このチュートリアルの解説内容を少し超えますが、 '*' の基本的な意味は"それら全て"です。
-- ポートは単純であり、それはシステムにより維持される 65535 (!) までの"ポート"の一覧です
-- …実際は単なる数値です。 要点は特定のポートへ送信する場合、 
-- その後に"リスニング"中のポートのみ受信可能であり、 
-- 同様にリスニング中のポートへ送信されたデータのみ読み取ることができます。
-- 概して言えば、どの機器と対話を希望するかがアドレスであり、一方では対話を希望する機器側でプログラムを行うものがポートです。
--
-- [注釈: 一部のオペレーティングシステムにおいて、 0 から 1024 までのポートは 
-- "特権があるプロセス用に予約されています"。それらのシステムに対しては安全対策をしてください。
-- 概して言えば、多くの問題を回避するために対象範囲のポートを使用しないでください。]
udp:setsockname('*', 12345)

local world = {} -- 世界の状態は空です

-- ローカル変数群を全て宣言して後述のメインサーバーのループで使用します。 
-- 恐らくクライアントの用例から一部を認識しますが、
-- どうして朗々とした 'msg_or_ip'? 'port_or_nil'? の名前であるのか
-- 恐らく不思議に思うでしょう。
-- 
-- さて、今回は僅かに異なる関数を使用しており、そのときにどうなるか理解するでしょう。
local data, msg_or_ip, port_or_nil
local entity, cmd, parms
-- 無限ループは LOVE だけを知っている場合は恐らく使用されたことがないでしょうが、 
-- それらは非常に一般的です。そして実は LOVE に心臓はありますが、
-- 一切見ることはできません。
-- 不注意ですが、サーバー用のあるものを必要とします。
-- さらにこの小さな変数は対象の*停止*をします。 :3
local running = true

-- 適切なループの開始…
print "Beginning server loop."
while running do
	-- この次の行はお馴染みの様に見えますし、確かにそうですが、今回は 'udp:receivefrom()' を
	-- 使用しています。受信は類似していますが、返されるデータは、送信側の
	-- IP アドレスであり、さらに送信側のポートです (対象へメッセージを送信するために
	-- 二種類の必要とされる事項を認識することが望ましい)。
	-- このクライアントの用例ではサーバーに対してソケットを割り当てる
	-- 必要はありませんが、割り当て済み以外のソースから来た
	-- 転送元のメッセージを無視するため、
	-- サーバーとしては全く役に立ちません。
	--
	-- [注釈: 厳密には、クライアントにて udp:receivefrom() (および 
	-- その相手方である udp:sendto() ) を使用することができます。確かに、それを妨げる 
	-- 関数に関しては特別なものは何もありません。send/receive は便宜的な
	-- 関数であり、実際は sendto/receivefom が処理を担当します ]
	data, msg_or_ip, port_or_nil = udp:receivefrom()
	if data then
		-- これら多くの素晴らしいパターンと一致します!
		entity, cmd, parms = data:match("^(%S*) (%S*) (.*)")
		if cmd == 'move' then
			local x, y = parms:match("^(%-?[%d.e]*) (%-?[%d.e]*)$")
			assert(x and y) -- 検証は良いことですが、アサーションは役立つものです。
			-- 忘れないで欲しいことは、"数値"と一致した場合でもまだ結果は文字列のままであることです!
			-- Lua の tonumber() を使用するお陰で変換は容易になります。
			x, y = tonumber(x), tonumber(y)
			-- それは最終的にずっと隠匿されます
			local ent = world[entity] or {x=0, y=0}
			world[entity] = {x=ent.x+x, y=ent.y+y}
		elseif cmd == 'at' then
			local x, y = parms:match("^(%-?[%d.e]*) (%-?[%d.e]*)$")
			assert(x and y) -- 検証は良いことですが、アサーションは役立つものです。
			x, y = tonumber(x), tonumber(y)
			world[entity] = {x=x, y=y}
		elseif cmd == 'update' then
			for k, v in pairs(world) do
				udp:sendto(string.format("%s %s %d %d", k, 'at', v.x, v.y), msg_or_ip,  port_or_nil)
			end
		elseif cmd == 'quit' then
			running = false;
		else
			print("unrecognised command:", cmd)
		end
	elseif msg_or_ip ~= 'timeout' then
		error("Unknown network error: "..tostring(msg))
	end
	
	socket.sleep(0.01)
end

print "Thank you."

-- これで UDP サーバーの用例は終了です。

そのほかの言語