isaacsloan
isaacsloan

Reputation: 895

How would I set up a simple unix socket server in crystal that could communicate with multiple clients?

I'm trying to figure out how to implement unix sockets in crystal. I'd like to be able to send a name to a server app and have it return "Hello #{name}."

#server.cr
require "socket"

loop do
  spawn do
    server = UNIXServer.new("/tmp/myapp.sock")
    name = server.gets
    server.puts "Hello #{name}."
  end
end

On the client I assume I could just have a loop that waits for standard in and sends it over the socket.

#client.cr
require "socket"

loop do
  sock = UNIXSocket.new("/tmp/myapp.sock")
  puts "What is your name?\n: "
  name = gets
  sock.puts name
  puts sock.gets
  sock.close
end

Obviously I'm missing something vital here, but I can't seem to find the right things in the documentation to fill in the blanks. What is the connections between UNIXServer and UNIXSocket? If someone could show me a working example of what I'm trying to do I would be forever grateful.

Update: Here's my Solution


It turns out that using UNIXServer and calling accept on it to create a socket solved my initial issue. After than I ran into the issue that all of the Fibers were using the same socket so closing one closed all of them. There's probably another solution but this works for me. Thanks to @RX14 for all the help.

#server.cr
require "socket"

server = UNIXServer.new("/tmp/cr.sock")

while sock = server.accept 
  proc = ->(sock : UNIXSocket) do
    spawn do
      name = sock.gets
      unless name == "q"
        puts name
        sock.puts "Hello #{name}."
        sock.close
      else
        server.close
        exit
      end
    end
  end
  proc.call(sock)
end

#client.cr
require "socket"

UNIXSocket.open("/tmp/cr.sock") do |sock|
  puts "What is your name?"
  name = gets
  sock.puts name
  puts sock.gets
  sock.close
end

Upvotes: 3

Views: 282

Answers (1)

Stephie
Stephie

Reputation: 3175

You need to use either UNIXServer#accept or UNIXServer#accept? methods to accept a incoming connection.

# server.cr
require "socket"

def handle_connection(socket)
  name = socket.gets
  socket.puts "Hello #{name}."
end

server = UNIXServer.new("/tmp/myapp.sock")
while socket = server.accept
  spawn handle_connection(socket)
end

# client.cr
require "socket"

UNIXSocket.open("/tmp/myapp.sock") do |sock|
  puts "What is your name?\n: "
  name = STDIN.gets
  sock.puts name
  puts sock.gets
end

Upvotes: 3

Related Questions