lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


2012/11/5 Hiroaki Nakamura <hnakamur@gmail.com>
> I've made an experimental module named "couv".
> https://github.com/hnakamur/couv
>
> It's a coroutine based libuv wrapper.
> It uses coroutines instead of callbacks (except for Stream:listen(),
> Timer:start() and spawn()).
>
> I think the benefits of using coroutines are:
> * We can write non-blocking applications which looks like good old
> blocking codes wrapped with
>   coroutine.wrap().
>   Please see a tcp echo server and client example.
>
> https://github.com/hnakamur/couv/blob/master/examples/tcp-echo-server.lua
>
> https://github.com/hnakamur/couv/blob/master/examples/tcp-echo-client.lua
> * We can use pcall() to catch errors. We don't need to check every
> return value for errors.
>
> It is not finished yet and APIs may change.
> Currently example and test codes are working, though some tests fail on
> Windows.
>
> I would like to ask you what do you think about it.

I'm working on a very similar high level wrapping code to write code
blocking-style without actually blocking the Lua interpreter. It's
unfortunately not yet ready for release, but you may be interested by
the syntax since I tried to simplify it to the minimum. Below is for
example how I'd write the echo server that you give as example. It's
of a similar length to your example, but that's because of the QUIT
command handling code that's a bit harder (my lib doesn't assemble
text lines). On the other hand the network code itself is shorter.

local nb = require 'nb'

local TEST_PORT = 9123

local lt -- listening thread
lt = nb.add_thread(function()
	local l = nb.tcp() -- listening socket
	l:bind('*', TEST_PORT)
	l:listen()
	while true do
		local s = l:accept() -- server socket
		nb.add_thread(function()
			local buffer = "\n"
			while true do
				local byte,msg = s:read(1)
				if not byte then
					break
				end
				s:write(byte)
				-- handle QUIT
				buffer = buffer..byte
				if buffer:match('[\r\n]QUIT[\r\n]$') then
					nb.kill_thread(lt)
					l:close()
					break
				end
				-- keep only "QUIT" and preceding newline
				buffer = buffer:sub(-5)
			end
			s:close()
		end)
	end
end)

nb.run()

Note that I didn't run your example but merely read the source, so I
may have missed some feature or behaviour detail. If you want to test
it for yourself, it's on BitBucket and the LuaSocket-based back-end
should work as-is:

https://bitbucket.org/doub/nb2/src/tip/engine_luasocket/nb.lua