Code from here - https://crystal-lang.org/api/0.21.1/UNIXServer.html
require "socket"
server = UNIXServer.new("/tmp/myapp.sock")
message = server.gets
server.puts message
Error:
laptop% ~/crystal-0.21.1-1/bin/crystal run ./test.cr
Error reading file: Invalid argument (Errno)
0x449c4f: *UNIXServer at /home/sorcus/crystal-0.21.1-1/src/io/file_descriptor.cr 249:9
0x449f46: *UNIXServer at /home/sorcus/crystal-0.21.1-1/src/io/buffered.cr 208:12
0x44a024: *UNIXServer at /home/sorcus/crystal-0.21.1-1/src/io/buffered.cr 84:7
0x44966f: *UNIXServer at /home/sorcus/crystal-0.21.1-1/src/io.cr 700:37
0x44947f: *UNIXServer at /home/sorcus/crystal-0.21.1-1/src/io.cr 674:5
0x449441: *UNIXServer at /home/sorcus/crystal-0.21.1-1/src/io.cr 644:5
0x44941f: *UNIXServer at /home/sorcus/crystal-0.21.1-1/src/io.cr 642:3
0x42af60: ??? at /home/sorcus/test.cr 4:11
0x430d39: main at /home/sorcus/crystal-0.21.1-1/src/main.cr 12:15
0x7f412700c511: __libc_start_main at ??
0x42a87a: _start at ??
0x0: ??? at ??
Right, the example cannot work, because we can't simply read from a UNIXServer
, the server needs to accept a client, then use this client to interact, like:
server = UNIXServer.new("/tmp/myapp.sock")
puts "waiting for client on /tmp/myapp.sock"
client = server.accept
message = client.gets
client.puts message
server.close
Then using another program, you can interact with the UNIXServer
with a UNIXSocket
:
client = UNIXSocket.new("/tmp/myapp.sock")
client.puts "Hello world"
puts "server replied"
puts client.gets
We'll need to change the documentation (and some other things too, @ysbaddaden )
I also think it's a mistake that TCPServer
and UnixServer
inherit Socket and that they are IOs, because you can't read/write from them, only accept connections, so the above should simply not even compile.
An experiment based on @bew comment:
require "socket"
server = UNIXServer.new("/tmp/myapp.sock")
CLIENTS = [] of UNIXSocket
Signal::INT.trap {
puts "closing server..."
server.close
exit
}
def on_message(client)
loop {
msg = client.gets
if msg == "quit"
puts "deleting client..."
CLIENTS.delete client
pp CLIENTS.size
break
else
yield msg
end
}
end
loop {
puts "waiting for client on /tmp/myapp.sock"
new_client = server.accept
spawn {
on_message(new_client) {|msg|
CLIENTS.each {|client|
client.puts msg unless client == new_client
}
}
}
CLIENTS << new_client
pp CLIENTS.size
}
require "socket"
client = UNIXSocket.new("/tmp/myapp.sock")
Signal::INT.trap {
client.puts "quit"
exit
}
print "name: "
name = gets.to_s
spawn {
loop {
msg = client.gets
if msg
puts msg
else
puts "server closed"
exit
end
}
}
loop {
msg = gets.to_s
client.puts "#{name}: #{msg}"
}
$ crystal socket_server.cr
waiting for client on /tmp/myapp.sock
CLIENTS.size # => 1
waiting for client on /tmp/myapp.sock
CLIENTS.size # => 2
waiting for client on /tmp/myapp.sock
$ crystal socket_client.cr
name: program1
hi, I'm p1
program2: Hi p1!!!
$ crystal socket_client.cr
name: program2
program1: hi, I'm p1
Hi p1!!!
Happy crystalling :smile:
@asterite well, TCP and UNIX servers are TCP and UNIX sockets, though they won't act as IO, but then: UDP sockets are both server/client...
Most helpful comment
I also think it's a mistake that
TCPServer
andUnixServer
inherit Socket and that they are IOs, because you can't read/write from them, only accept connections, so the above should simply not even compile.