Last active
March 26, 2020 01:43
-
-
Save niku/85a247be3d72fd7fa58d999f0903429f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 比較用 | |
# https://elixir-lang.org/getting-started/mix-otp/task-and-gen-tcp.html | |
defmodule KVServer do | |
require Logger | |
@doc """ | |
Starts accepting connections on the given `port`. | |
""" | |
def accept(port) do | |
{:ok, socket} = :gen_tcp.listen(port, | |
[:binary, packet: :line, active: false, reuseaddr: true]) | |
Logger.info "Accepting connections on port #{port}" | |
loop_acceptor(socket) | |
end | |
defp loop_acceptor(socket) do | |
{:ok, client} = :gen_tcp.accept(socket) | |
{:ok, pid} = Task.Supervisor.start_child(KVServer.TaskSupervisor, fn -> serve(client) end) | |
:ok = :gen_tcp.controlling_process(client, pid) | |
loop_acceptor(socket) | |
end | |
defp serve(socket) do | |
socket | |
|> read_line() | |
|> write_line(socket) | |
serve(socket) | |
end | |
defp read_line(socket) do | |
{:ok, data} = :gen_tcp.recv(socket, 0) | |
data | |
end | |
defp write_line(line, socket) do | |
:gen_tcp.send(socket, line) | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# https://elixir-lang.org/getting-started/mix-otp/task-and-gen-tcp.html にある | |
# Elixir製のEchoサーバーをRubyのRactorを使って書いてみるとこうなるかなという想像。 | |
# | |
# https://docs.ruby-lang.org/ja/latest/class/TCPServer.html | |
# にあるTCPServerの例も参考にした。 | |
require "socket" | |
class EchoServer | |
def init(port) | |
@port = port | |
end | |
def accept() | |
socket = TCPServer.open(@port) | |
addr = socket.addr | |
addr.shift | |
printf("server is on %s\n", addr.join(":")) | |
loop_acceptor(socket) | |
end | |
private | |
def loop_acceptor(socket) | |
loop do | |
client = socket.accept | |
# もしEchoServerをシャットダウンするときに子の接続が全部なくなるまで待つならractorを配列で保持しておかないといけないな | |
Ractor.new client do |c| | |
# Ractor#receive しない限りエラーが親に影響を及ぼさないのでエラーハンドリングしなくてもいいや | |
serve(c) | |
end | |
# :gen_tcp.controlling_process(client, pid) | |
# は下記のとおりErlangVM特有の話だと思うのでRubyでは考慮しなくていいや | |
# This makes the child process the “controlling process” of the client socket. | |
# If we didn’t do this, the acceptor would bring down all the clients if it crashed | |
# because sockets would be tied to the process that accepted them (which is the default behaviour). | |
end | |
end | |
def serve(socket) | |
loop do | |
s.write(s.gets) | |
end | |
end | |
end | |
EchoServer.new(8080).accept() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment