I am using lua-websockets https://github.com/lipp/lua-websockets to try and get a web socket server running.
Using the copas example they provided:
local copas = require'copas'
local server = require'websocket'.server.copas.listen
{
port = 8080,
protocols = {
echo = function(ws)
while true do
local message = ws:receive()
if message then
ws:send(message)
else
ws:close()
return
end
end
end
}
}
copas.loop()
This works and starts listening on port 8080 and I am able to connect and get a echo response back.
The problem is when I try and integrate it with heka. I start heka and it starts the websocket server but hangs at Loading plugin. When it tries to "load" a plugin, it executes the lua script.
Now my question is, how do I run the websocket server and send a "success" to heka to let it continue start up. Simply this would be: if the websocket is listening on 8080 return to heka and say the lua script has been executed successfully.
Thanks in advance!
Don't call copas.loop() as it enters an indefinite loop that handles all copas socket interactions. You need to use copas.step() instead (see controlling copas section) and call it at the appropriate time from your heka code (this call will return false on timeout and true when it handles something). In a GUI application it may be called from an IDLE handler.
Related
I am using NodeMCU (with ESP8266-E) with an upgraded firmware. All basic commands work perfectly but there is one problem.
I wanted to create an independent access point, which could have a behaviour like a UDP server. That means without direct connection to any other access points. A simple UDP server like soft AP.
I followed these steps:
I have uploaded a new firmware to NodeMCU.
I have downloaded ESPlorer for better work with NodeMCU.
I have uploaded the source code below.
I have connected to the NodeMCU access point on my desktop.
I have sent some strings to the NodeMCU using a Java UDP client program.
I have looked at the messages on ESPlorer.
NodeMCU has not received any such strings.
--
print("ESP8266 Server")
wifi.setmode(wifi.STATIONAP);
wifi.ap.config({ssid="test",pwd="12345678"});
print("Server IP Address:",wifi.ap.getip())
-- 30s timeout for an inactive client
srv = net.createServer(net.UDP, 30)
-- server listens on 5000, if data received, print data to console
srv:listen(5000, function(sk)
sk:on("receive", function(sck, data)
print("received: " .. data)
end)
sk:on("connection", function(s)
print("connection established")
end)
end)
When I tried to send a message using a Java application, there was no change in ESPlorer. Not even when I tried to send a message using the Hercules program (great program for TCP, UDP communication).
I guess that maybe it will be the wrong IP address. I am using the IP address of the AP and not the IP address of the station.
In other words I am using this address: wifi.ap.getip() and not this address wifi.sta.getip() for connections to the UDP server. But sta.getip() returns a nil object. Really I don't know.
I will be glad for any advice.
Thank you very much.
Ok, let's restart this since you updated the question. I should have switched on my brain before I gave you the first hints, sorry about this.
UDP is connectionless and, therefore, there's of course no s:on("connection"). As a consequence you can't register your callbacks on a socket but on the server itself. It is in the documentation but it's easy to miss.
This should get you going:
wifi.setmode(wifi.STATIONAP)
wifi.ap.config({ ssid = "test", pwd = "12345678" })
print("Server IP Address:", wifi.ap.getip())
srv = net.createServer(net.UDP)
srv:listen(5000)
srv:on("receive", function(s, data)
print("received: " .. data)
s:send("echo: " .. data)
end)
I ran this against a firmware from the dev branch and tested from the command line like so
$ echo "foo" | nc -w1 -u 192.168.4.1 5000
echo: foo
ESPlorer then also correctly printed "received: foo".
This line is invalid Lua code. connected is in the wrong place here. you can't just put a single word after a function call.
print(wifi.ap.getip()) connected
I guess you intended to do something like
print(wifi.ap.getip() .. " connected")
Although I think you should add som error handling here in case wifi.ap.getip() does not return an IP.
Here you do not finish the function definition. Neither did you complete the srv:on call
srv:on("receive", function(srv, pl)
print("Strings received")
srv:listen(port)
I assume you just did not copy/paste the complete code.
I'm trying to understand the socket class and i'm using the following example to implement a server sample
local server = assert(socket.bind("*", 0))
-- find out which port the OS chose for us
local ip, port = server:getsockname()
-- print a message informing what's up
print("Please telnet to localhost on IP [" ..ip.. "] and port [" .. port .. "]")
print("After connecting, you have 10s to enter a line to be echoed")
-- loop forever waiting for clients
while true do
-- wait for a connection from any client
local client = server:accept()
-- make sure we don't block waiting for this client's line
client:settimeout(10)
-- receive the line
local line, err = client:receive()
-- if there was no error, send it back to the client
if not err then
client:send(line .. "\n")
end
-- done with client, close the object
client:close()
end
But now the question is, how can I telnet for example the address localhost:8080 via lua?
EDIT:
I forgot to tell something, I don´t even can telnet on cmd. When I type the command:
telnet ip port
it always says "connection lost" after I send a message. What am I doing wrong?
First, follow the instructions from here to enable telnet in Windows 7:
Go to Control Panel
Find Turn Windows features on or off under Programs (depending on layout)
Find Telnet client and enable it.
Once you've done that, it should work as expected.
Done!
local socket = require("socket")
local server = socket.connect(ip, port)
local ok, err = server:send("RETURN\n")
if (err ~= nil) then
print (err)
else
while true do
s, status, partial = server:receive(1024)
print(s or partial)
if (status == "closed") then
break
end
end
end
server:close()
I'm getting messages of a RabbitMQ queue and each message is a URL that I want to make a request to. Now I'm using the AMQP gem to subscribe to the queue and that uses EventMachine, so I'm using the the em-http-request library to make the http requests. According to the documentation here: https://github.com/igrigorik/em-http-request/wiki/Parallel-Requests
The following will issue asynchronous http-requests:
EventMachine.run {
http1 = EventMachine::HttpRequest.new('http://google.com/').get
http2 = EventMachine::HttpRequest.new('http://yahoo.com/').get
http1.callback { }
http2.callback { }
end
So when I subscribe to the RabbitMQ queue I have the following code:
x = 0
EventMachine.run do
connection = AMQP.connect(:host => '127.0.0.1')
channel = AMQP::Channel.new(connection)
channel.prefetch(50)
queue = channel.queue("http.requests")
exchange = channel.direct("")
queue.subscribe do |metadata, payload|
url = payload.inspect
eval "
#http#{x} = EventMachine::HttpRequest.new(url).get
#http#{x}.callback do
puts \"got a response\"
puts #http#{x}.response
end
x = x+1
"
end
end
This dynamically creates new variables and creates new http requests, similar to the way described in the em-http-request documentation. But is there a way to test whether the requests are actually being made asynchronously? Is it possible to write to the console every time a get request is fired off so I can see they are fired off one after the other without waiting for a response?
You can try running tcpdump and analysing the output. If you see the TCP three-way handshakes for the two connections being interleaved then the connections are happening in parallel.
This can't really be part of an automated test though, if that's what you're trying to aim for. I would be happy just to verify that the library does what it says it does once and not make it part of a test suite.
A very simple example, demonstrating exactly what you want:
require 'em-http-request'
EM.run do
# http://catnap.herokuapp.com/3 delays the HTTP response by 3 seconds.
http1 = EventMachine::HttpRequest.new('http://catnap.herokuapp.com/3').get
http1.callback { puts 'callback 1' }
http1
puts 'fired 1'
http2 = EventMachine::HttpRequest.new('https://www.google.com/').get
http2.callback { puts 'callback 2' }
puts 'fired 2'
end
Output (for me):
fired 1
fired 2
callback 2
callback 1
Depending on your internet connection, Heroku and Google, the response to the second HTTP request will likely come in first and you can be sure, the requests are indeed done in parallel.
Environment: Mac osx lion
Grails version: 2.1.0
Java: 1.7.0_08-ea
If I start up vertx in embedded mode within Bootstrap.groovy and try to hit the same websocket endpoint through multiple browsers, the requests get queued up.
So depending on the timing of the requests, after one request is done with its execution the next request gets into the handler.
I've tried this with both websocket and SockJs and noticed the same behavior on both.
BootStrap.groovy (SockJs):
def vertx = Vertx.newVertx()
def server = vertx.createHttpServer()
def sockJSServer = vertx.createSockJSServer(server)
def config = ["prefix": "/eventbus"]
sockJSServer.installApp(config) { sock ->
sleep(10000)
}
server.listen(8088)
javascript:
<script>
function initializeSocket(message) {
console.log('initializing web socket');
var socket = new SockJS("http://localhost:8088/eventbus");
socket.onmessage = function(event) {
console.log("received message");
}
socket.onopen = function() {
console.log("start socket");
socket.send(message);
}
socket.onclose = function() {
console.log("closing socket");
}
}
OR
BootStrap.groovy (Websockets):
def vertx = Vertx.newVertx()
def server = vertx.createHttpServer()
server.setAcceptBacklog(10000);
server.websocketHandler { ws ->
println('**received websocket request')
sleep(10000)
}.listen(8088)
javascript
socket = new WebSocket("ws://localhost:8088/ffff");
socket.onmessage = function(event) {
console.log("message received");
}
socket.onopen = function() {
console.log("socket opened")
socket.send(message);
}
socket.onclose = function() {
console.log("closing socket")
}
From the helpful folks at vertx:
def server = vertx.createHttpServer() is actually a verticle and a verticle is a single threaded process
As bluesman says, each verticle goes in its own thread. You can span your verticles across cores in your hardware, even clustering them with more machines. But this add capacity to accept simultaneous requests.
When programming realtime apps, we should try to build the response as soon as posible to avoid blocking. If you think your operation can be time intensive, consider this model:
Make a request
Pass the task to a worker verticle and assign this task an UUID (for example), and put it into response. The caller now knows that the work is in progress and receive the response so fast
When the worker ends the task, put a notification in event bus using the UUID assigned.
The caller check the event bus for the task result.
This is tipically done in a web application vía websockets, sockjs, etc.
This way you can accept thousands of request without blocking. And clients will receive the result without blocking the UI.
Vert.x use the JVM to create a so called "multi-reactor pattern", that is a reactor pattern modified to perform better.
As far as I understood is not true that each verticle has its own thread: the fact is that each verticle is always served by the same event loop, but more verticles can be binded with the same event loop and there can be multiple event loops. An event loop is basically a thread, so few threads should serve many verticles.
I didn't use vert.x in embedded mode (and I don't know if the main concept change) but you should perform much better instantiating many verticles for the job
Regards,
Carlo
As mentioned before Vertx concept is based on reactor pattern which means the single instance has at least one single-threaded event loop and processes events sequentially. Now the request processing may consist of several events, the point here is to serve the request and each event with non-blocking routines.
E.g. when you wait for Web Socket message the request should be suspended and in the event of message it is woken back. Whatever you do with the message should be also non-blocking thus asynchronous, like any file IO, networking IO, DB access. Vertx provides basic elements which you should use to build such async flow: Buffers, Pumps, Timers, EventBus.
To wrap it up - just never block. The use of sleep(10000) kills the concept. If you really need to halt the execution use VertX's Timers instead.
We have an app that invokes various remote methods on MBeans using MBeanServerConnection.invoke.
Occasionally one of these methods hangs.
Is there any way to have a timeout on the call? so that it will return with an exception if the call takes too long?
Or do I have to move all those calls into separate threads so they don't lock up the UI and require killing the app?
See http://weblogs.java.net/blog/emcmanus/archive/2007/05/making_a_jmx_co.html
===== Update =====
I was thinking about this stuff when I first responded, but I was on my mobile and I can't type worth a damn on it.....
This is really an RMI problem, and unless you use a different protocol, there's not much you can do, except, as you say, move all those calls into separate threads so they don't lock up the UI.
But.... if you have the option of fiddling with the target server and you can customize the connecting client, you have at least 1 option which is to customize the JMXConnectorServer on your target servers.
The standard JMXConnectorServer implementation is the RMIConnectorServer. Part of it's specification is that when you create a new instance using any of the constructors (like RMIConnectorServer(JMXServiceURL url, Map environment)), the environment map can contain a key/value pair where the key is RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE and the value is a RMIClientSocketFactory. Therefore, you can specify a socket factory method like this:
RMIClientSocketFactory clientSocketFatory = new RMIClientSocketFactory() {
public Socket createSocket(String host, int port) {
Socket s = new Socket(host, port);
s.setSoTimeout(3000);
}
};
This factory creates a Socket and then sets its SO_TIMEOUT using setSoTimeout, so when the client connects using this socket, all operations, including connecting, will timeout after 3000 ms.
You could also checkout the JMXMP connector and server in the jmx-optional package of the OpenDMK. (links are to my github mavenized). No built in solution, mind you, but they're super easy to extend and JMXMP is simple TCP socket based rather than RMI, so this type of customization would be trivial.
Cheers.
# Nicholas : The above code is not working.I mean request is not getting timeout after 3000. ms.
map.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE , new RMIClientSocketFactory() {
#Override
public Socket createSocket(String host, int port) throws IOException {
if(logger.isInfoEnabled() ){
logger.info("JMXManager inside createSocket..." + host + ": port :" + port);
}
Socket s = new Socket(host, port);
s.setSoTimeout(3000);
return s;
}
});
cs = JMXConnectorServerFactory.newJMXConnectorServer(url,map,mbeanServer);
As I answered on: How to set request timeout for JMX Connector the RMI properties can help you. All the properties are on Oracle documentation site:
http://docs.oracle.com/javase/7/docs/technotes/guides/rmi/sunrmiproperties.html.
For example: -Dsun.rmi.transport.tcp.responseTimeout=60000 is a client side tcp response timeout. There are also properties for connect timeout and for server side connections.
I also am not happy how the JMX/RMI/TCP stack hides important settings from lower level protocols, and makes it not available for a single connection.