I've this Ruby server that uses a Unix Socket:
require 'socket'
server = UNIXServer.new('/tmp/ciccio.sock')
loop do
sock = server.accept
loop do
begin
data = sock.recv(1024)
data = "DO SOMETHING -> #{data}"
sock.write(data)
sock.flush
rescue Errno::EPIPE, Errno::ENOTCONN
break
end
end
end
And I've this client in JavaScript that uses node.js net api:
Net = require('net');
var client = Net.connect({path: '/tmp/ciccio.sock'}, () => {
console.log('write data');
client.write('hello world!');
});
client.on('data', (data) => {
console.log(data.toString());
client.end();
});
client.on('end', () => {
console.log('end');
});
client.on('error', (error) => {
console.log(error.toString());
});
The problem is that at the first iteration of server loop, recv receives the right string and the server replies to the client with the string data. But at the second iteration recv receives empty data and so a infinite loop begins... server continues to receive empty data and recv does not block...
If I use a ruby client like this all works fine...
require 'socket'
sock = UNIXSocket.new('/tmp/ciccio.sock')
loop do
sock.write('hello world!')
data = sock.recv(1024)
puts data
sleep(10)
end
sock.close
Your client closes the connection upon connecting, writing "hello world", and then receiving a response. Now your server is calling recv on a socket that has been closed, which will return an empty string. Since you're looping to read on this socket indefinitely, it will never return control back to the outer loop to call accept for the second client. The ruby version of your client works because it never closes the connection to the server.
Breaking out of your inner loop after receiving an empty string should get you what you want,
require 'socket'
server = UNIXServer.new('/tmp/ciccio.sock')
loop do
sock = server.accept
loop do
begin
data = sock.recv(1024)
break if data.empty?
data = "DO SOMETHING -> #{data}"
sock.write(data)
sock.flush
rescue Errno::EPIPE, Errno::ENOTCONN
break
end
end
end
Another potential problem is that your server can only service a single connection to a single client, as the inner loop blocks any subsequent calls to accept until the current connection ends.
Related
I am using Julia's SimpleWebSockets to open a websocket connection. I want it to reconnect after any disconnects. Something is wrong with the notify commented below, it doesnt run after disconnect, thereby preventing the rest of the code from continuing.
using SimpleWebsockets
function connect_loop(C::Coinbase, msg_channel::Channel)
while true
client = WebsocketClient()
ended = Condition()
listen(client, :connect) do ws
listen(ws, :message) do message
put!(msg_channel, message)
end
listen(ws, :error) do reason
#warn "Websocket connection error" reason...
notify(ended)
end
listen(ws, :close) do reason
#warn "Websocket connection closed" reason...
notify(ended)
end
# for msg in C.command_channel
# send(ws, JSON.json(msg))
# end
end
listen(C.client, :connectError) do err
println("Websocket Connect Error.")
notify(ended) # This is not working !!!!!!!!!
end
println("connecting")
#async open(C.client, "wss://ws-feed.pro.coinbase.com")
println("wait for ended")
wait(ended)
println("ended")
sleep(2)
end
end
Procedure is to connect on Wifi, then after successful connection disable the wifi and we should see it go into a reconnect loop, but instead it just stalls waiting on that notify call.
connecting
wait for ended
┌ Warning: Websocket connection closed
│ code = 1006
│ description = "could not ping the server."
└ # Main ~/src/tibra/Tibra.jl/src/MarketDataIO/Coinbase.jl:60
ended
connecting
wait for ended
Websocket Connect Error.
Here is my code (and below it is my issue):
require "socket"
server = TCPServer.open("localhost", 2000)
loop {
thread.start(server.accept) do |nodervcr|
msg = nodervcr.gets
puts(msg)
if msg = "codeword"
puts("codeword!")
else
puts("not codeword")
# Note this part works: it sends the server a message and it displays it
# You would think a simple if then else statement could redirect it according to the imcoming message from the client; which is my issue.
end
}
So I tried:
if msg == code
# then do this
elsif msg == code2
# then do this
# etc
But it's not working.
I've tried replacing msg with nodervcr, still nothing.
The strange part is that it's obviously getting the message, and msg does = what the client sends.. but it acts as if that variable dies immediately. I'm new to ruby. please help thanks.
You have a few problems in your code. But the main problem is that when you use something like Telnet, you probally are giving a enter.
So your sending "codeword" + CRLF (codeword\r\n). Thats not the same as your check: msg == "codeword"
What you should do is strip the input from these chars (strip). It removes the CRLF and it then works
Remember. Variable Assignments are = (single) comparing is double ==
Below the working code:
require "socket"
server = TCPServer.open("127.0.0.1", 2000)
loop {
Thread.start(server.accept) do |nodervcr| # Thread, not thread
msg = nodervcr.gets
# puts(msg)
p msg # use this so see all the invisiable chars
if msg.strip == "codeword" # stip the input
puts("codeword!")
else
puts("not codeword")
end
# Note this part works: it sends the server a message and it displays it
# You would think a simple if then else statement could redirect it according to the imcoming message from the client; which is my issue.
end
}
I am new to lua programming and trying to implement Lua-websocket in openwrt as a client. here is the library.
Was trying to use client copas library but the issue is the script is getting stopped listening server after executing once (i.e. connecting to server, receiving message, sending message). I want the script to always listen the server without any timeout or script halt.
Below is the script
local copas = require'copas'
local websocket = require'websocket'
local json = require('json')
local client = require 'websocket.client'.new()
local ok,err = client:connect('ws://192.168.1.250:8080')
if not ok then
print('could not connect',err)
end
local ap_mac = { command = 'subscribe', channel = 'test' }
local ok = client:send(json.encode(ap_mac))
if ok then
print('msg sent')
else
print('connection closed')
end
local message,opcode = client:receive()
if message then
print('msg',message,opcode)
else
print('connection closed')
end
local replymessage = { command = 'message', message = 'TEST' }
local ok = client:send(json.encode(replymessage))
if ok then
print('msg sent')
else
print('connection closed')
end
copas.loop()
Here copas.loop() is not working.
On openWrt I had installed lua 5.1
Short answer: you do not use Copas correctly.
In detail: copas.loop does nothing, because you have neither created a Copas server, nor a Copas thread. Check the Copas documentation.
The send and receive actions in your script are performed outside Copas, because they are not within a Copas.addthread (function () ... end). You also create a websocket client that is not a copas one, but a synchronous one (the default). Check the lua-websocket documentation and its examples.
The solution:
local copas = require'copas'
local websocket = require'websocket'
local json = require'cjson'
local function loop (client)
while client.state == "OPEN" do
local message, opcode = client:receive()
... -- handle message
local replymessage = { command = 'message', message = 'TEST' }
local ok, err = client:send(json.encode(replymessage))
... -- check ok, err
end
end
local function init ()
local client = websocket.client.copas ()
local ok,err = client:connect('ws://192.168.1.250:8080')
... -- check ok, err
local ap_mac = { command = 'subscribe', channel = 'test' }
ok, err = client:send(json.encode(ap_mac))
... -- check ok, err
copas.addthread (function ()
loop (client)
end)
end
copas.addthread (init)
copas.loop()
The init function instantiates a client for Copas. It also starts the main loop in a Copas thread, that waits for incoming messages as long as the connection is open.
Before starting the Copas loop, do not forget to add a Copas thread for the init function.
I have 2 very simple Vertx verticles written in Ruby:
### sender.rb
require 'vertx/vertx'
require 'date'
vertx = Vertx::Vertx.vertx()
event_bus = vertx.event_bus()
vertx.set_periodic(2000) { |v|
msg = "Ruby NOW " + DateTime.now.strftime("%H:%M:%S")
puts(msg)
event_bus.publish("news.uk.sport", msg)
}
and
### listener.rb
require 'vertx/vertx'
vertx = Vertx::Vertx.vertx()
event_bus = vertx.event_bus()
consumer = event_bus.consumer("news.uk.sport")
consumer.handler() { |message|
puts "I have received a message: #{message.body()}"
}
consumer.completion_handler() { |res_err,res|
if (res_err == nil)
puts "The handler registration has reached all nodes"
else
puts "Registration failed!"
end
}
I have constructed these two verticles exactly from the code examples from vertx.io documentation.
I open 2 terminal sessions.
In 1st terminal I deploy the sender.rb verticle:
$ vertx run sender.rb
in 2nd terminal i deploy listener.rb verticle:
$ vertx run listener.rb
The sender sends and prints messages, but listener, doesn't receive anything (no print output from listener.rb)
I have tried to run vertx with flags
-ha
and
-cluster
but it didn't help. Please help.
UPDATE
Many thanks to Tsegismont
I have re-implemented both the listener.rb and the sender.rb and it worked :)
Now i just have little question purely out of curiosity:
In my sender:
simple_eventbus git:(master) ✗ vertx run sender.rb -cluster
Starting clustering...
No cluster-host specified so using address 192.168.7.179
Thread Thread[vert.x-eventloop-thread-2,5,main] has been blocked for 2071 ms, time limit is 2000
Thread Thread[vert.x-eventloop-thread-2,5,main] has been blocked for 3073 ms, time limit is 2000
You're already on a Vert.x context, are you sure you want to create a new Vertx instance?
Succeeded in deploying verticle
On Sender site: We now have a clustered event bus: #<Vertx::EventBus:0x61deddf7>
The message has been sent: 13:20:13
The message has been sent: 13:20:15
The message has been sent: 13:20:17
The sender.rb is:
require 'vertx/vertx'
require 'date'
options = {
}
Vertx::Vertx.clustered_vertx(options) { |res_err,res|
if (res_err == nil)
vertx = res
event_bus = vertx.event_bus()
puts "On Sender site: We now have a clustered event bus: #{event_bus}"
vertx.set_periodic(2000) { |v|
msg = "Message from Sender: ruby message NOW " + DateTime.now.strftime("%H:%M:%S")
puts "The message has been sent: " + DateTime.now.strftime("%H:%M:%S")
event_bus.publish("news.uk.sport", msg)
}
else
puts "Failed: #{res_err}"
end
}
and my listener.rb output:
simple_eventbus git:(master) ✗ vertx run listener.rb -cluster
Starting clustering...
No cluster-host specified so using address 192.168.7.179
Thread Thread[vert.x-eventloop-thread-2,5,main] has been blocked for 2169 ms, time limit is 2000
Thread Thread[vert.x-eventloop-thread-2,5,main] has been blocked for 3172 ms, time limit is 2000
You're already on a Vert.x context, are you sure you want to create a new Vertx instance?
Succeeded in deploying verticle
On listener side: We now have a clustered event bus: #<Vertx::EventBus:0x44af7bbf>
The handler registration has reached all nodes
I have received a message: Message from Sender: ruby message NOW 13:20:13
I have received a message: Message from Sender: ruby message NOW 13:20:15
I have received a message: Message from Sender: ruby message NOW 13:20:17
The listener.rb code:
require 'vertx/vertx'
options = {
}
Vertx::Vertx.clustered_vertx(options) { |res_err,res|
if (res_err == nil)
vertx = res
event_bus = vertx.event_bus()
puts "On listener side: We now have a clustered event bus: #{event_bus}"
consumer = event_bus.consumer("news.uk.sport")
consumer.handler() { |message|
puts "I have received a message: #{message.body()}"
}
consumer.completion_handler() { |res_err,res|
if (res_err == nil)
puts "The handler registration has reached all nodes"
else
puts "Registration failed!"
end
}
else
puts "Failed: #{res_err}"
end
}
In my sender.rb the eventBus object assigned is:
#<Vertx::EventBus:0x61deddf7>
In my listener.rb it is different:
#<Vertx::EventBus:0x44af7bbf>
Is it just the object instance reference?
Doesn't have to be the same object instance to be shared?
And another question is why does it tell me onDeploy this?
Thread Thread[vert.x-eventloop-thread-2,5,main] has been blocked for 3073 ms, time limit is 2000
You're already on a Vert.x context, are you sure you want to create a new Vertx instance?
I have run the code once: vertx run listener.rb -cluster
Why does it tell me that I am already in Vertx context?
The problem is that your code creates a standalone Vert.x instance. To create a clustered Vert.x instance, follow this example:
require 'vertx/vertx'
options = {
}
Vertx::Vertx.clustered_vertx(options) { |res_err,res|
if (res_err == nil)
vertx = res
eventBus = vertx.event_bus()
puts "We now have a clustered event bus: #{eventBus}"
else
puts "Failed: #{res_err}"
end
}
from the Vert.x Event Bus clustering documentation section.
I have a client and server. I start up the server, and run the client, and the first time it works fine. The second time I run the client(without restarting the server), the client appears to hang. Can anyone see what is wrong?
I have a client:
# Code example originated from p069dtclient.rb at http://rubylearning.com/satishtalim/ruby_socket_programming.html
require 'socket'
x = 0;
streamSock = TCPSocket.new( 'localhost', 20000 )
while x < 10
streamSock.send( "Hello #{x}",0 )
str = streamSock.recv( 100 )
puts "#{x} " + str
x=x+1
end
streamSock.close
And server:
# p068dtserver.rb
require "socket"
dts = TCPServer.new('localhost', 20000)
s = dts.accept
print(s, " is accepted\n")
loopCount = 0;
loop do
Thread.start(s) do
loopCount = loopCount + 1
lineRcvd = s.recv(1024)
if ( !lineRcvd.empty? )
puts("#{loopCount} Received: #{lineRcvd}")
s.write(Time.now)
end
end
end
s.close
print(s, " is gone\n")
Each connection to the server requires a separate accept call in order to be received. What's happening is that you're accepting the first, working with it, and then effectively terminating while leaving the socket in a listening state. This means connections will be opened, but not accepted, so they hang as you describe.
You might be better off using a more robust server framework. EventMachine (http://rubyeventmachine.com/) is a little tricky to learn, but is far more powerful than a roll your own solution.
Here's a quick fix that might help:
require "socket"
dts = TCPServer.new('localhost', 20000)
while (s = dts.accept)
print(s, " is accepted\n")
loopCount = 0;
loop do
Thread.start(s) do
loopCount = loopCount + 1
lineRcvd = s.recv(1024)
if ( !lineRcvd.empty? )
puts("#{loopCount} Received: #{lineRcvd}")
s.write(Time.now)
end
end
end
s.close
print(s, " is gone\n")
end
Now the accept call is wrapped in a loop so more than one connection can be processed.