In need of Win32 fcntl (non-blocking)

I

Ivo Palli

Hi there,

I am making a multi-user, telnet based, bbs. At work I use Linux Ruby,
at home a Win32 port. (http://rubyinstaller.rubyforge.org/wiki/wiki.pl)

Now a multi-user server can be done in threads, but since I want to keep
it simple and avoid dead-locks and starvation problems, I decided not to
use threads. (I also read that threads can block the whole program if
they get stuck in system calls. That's not something I want.)

Instead I want to use a select, which is thankfully support in Ruby.
However a read to a socket which has data open always seems to block,
unless I specifically read what is available. Since I cannot know how
much data is waiting for me, I really need to do a non-blocking read. In
Linux it works, in Windows the fcntl call is not supported. :( As far as
I searched and tried, there is no other way to read data without blocking.

This guy

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/3155

seems to have made a fix some time ago. Can I ask why it is not in the
standard distribution? On that note, can somebody point me to a binary
win32 distribution that _does_ have this patch incorporated?

One last thing. I ran the example below on both Linux and Win32.
Normally stdout buffering is done up until a '\n' after which output is
flushed (ANSI C, both on Linux and Win32). This behaviour is seen on the
Linux Ruby port, but not under Win32 where I had to put in
'STDOUT.sync=true'. Can this be considered a bug?

I'm using:
ruby 1.8.2 (2004-12-25) [i386-mswin32]
ruby 1.8.2 (2004-12-25) [i686-linux]



Server example, works on Linux, not on Win32:

# socket example - server side
# usage: ruby svr.rb

require "socket"
require "fcntl"

gs = TCPserver.open(0)
addr = gs.addr
addr.shift
printf("server is on %s\n", addr.join(":"))
socks = [gs]

loop do
nsock = select(socks);
next if nsock == nil
for s in nsock[0]
if s == gs
ns = s.accept
ns.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
socks.push(ns)
print(s, " is accepted\n")
else
if s.eof?
print(s, " is gone\n")
s.close
socks.delete(s)
else
print "[" + s.read + "]\n"
end
end
end
end
 
T

Tanaka Akira

Ivo Palli said:
Instead I want to use a select, which is thankfully support in Ruby.
However a read to a socket which has data open always seems to block,
unless I specifically read what is available. Since I cannot know how
much data is waiting for me, I really need to do a non-blocking read. In
Linux it works, in Windows the fcntl call is not supported. :( As far as
I searched and tried, there is no other way to read data without blocking.

sysread might be usable because sysread doesn't block when some data
available. If sysread is usable, you don't need non-blocking read.

require "socket"

gs = TCPserver.open(0)
addr = gs.addr
addr.shift
printf("server is on %s\n", addr.join(":"))
socks = [gs]

loop do
nsock = select(socks);
next if nsock == nil
for s in nsock[0]
if s == gs
ns = s.accept
socks.push(ns)
print(s, " is accepted\n")
else
begin
print "[" + s.sysread(4096) + "]\n"
rescue EOFError
print(s, " is gone\n")
s.close
socks.delete(s)
end
end
end
end
 
I

Ivo Palli

You are correct, sysread() returns without blocking. However this is a
workaround at best. In the interest of portability over platforms, I
still recommend for fcntl() to be implemented in the Win32 platform.
Afterall Ruby aims to provide a unified platform regardless of OS. Right?

Are there any ways to detect the OS btw? If I'm going to run my script
on multiple platforms, and I need to workaround, how can I do this
automatically?

Regards,

Ivo Palli

Tanaka said:
Instead I want to use a select, which is thankfully support in Ruby.
However a read to a socket which has data open always seems to block,
unless I specifically read what is available. Since I cannot know how
much data is waiting for me, I really need to do a non-blocking read. In
Linux it works, in Windows the fcntl call is not supported. :( As far as
I searched and tried, there is no other way to read data without blocking.


sysread might be usable because sysread doesn't block when some data
available. If sysread is usable, you don't need non-blocking read.

require "socket"

gs = TCPserver.open(0)
addr = gs.addr
addr.shift
printf("server is on %s\n", addr.join(":"))
socks = [gs]

loop do
nsock = select(socks);
next if nsock == nil
for s in nsock[0]
if s == gs
ns = s.accept
socks.push(ns)
print(s, " is accepted\n")
else
begin
print "[" + s.sysread(4096) + "]\n"
rescue EOFError
print(s, " is gone\n")
s.close
socks.delete(s)
end
end
end
end
 
D

Daniel Berger

Ivo said:
Are there any ways to detect the OS btw? If I'm going to run my script
on multiple platforms, and I need to workaround, how can I do this
automatically?

Regards,

Ivo Palli

If you just need to detect Windows vs Unix, you can use
File::ALT_SEPARATOR. It's only true on Win32.

If you want a little more detail, you can use the RUBY_VERSION
constant.

If you want a lot more detail, see sys-uname, available on the RAA.
Regards,

Dan
 
N

nobu.nokada

Hi,

At Wed, 26 Jan 2005 00:00:58 +0900,
Ivo Palli wrote in [ruby-talk:128097]:
This guy

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/3155

seems to have made a fix some time ago. Can I ask why it is not in the
standard distribution? On that note, can somebody point me to a binary
win32 distribution that _does_ have this patch incorporated?

[ruby-core:3157] has been committed to CVS HEAD instead, but
not backported to 1.8 yet.
 
J

Joao Pedrosa

Hi,

Hi,

At Wed, 26 Jan 2005 00:00:58 +0900,
Ivo Palli wrote in [ruby-talk:128097]:
This guy

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/3155

seems to have made a fix some time ago. Can I ask why it is not in the
standard distribution? On that note, can somebody point me to a binary
win32 distribution that _does_ have this patch incorporated?

[ruby-core:3157] has been committed to CVS HEAD instead, but
not backported to 1.8 yet.

This is good news. I'm going to test this later. Thanks!

Regards,
Joao
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,152
Members
46,698
Latest member
LydiaHalle

Latest Threads

Top