Problem with sockets

  • Thread starter Pierre Barbier de Reuille
  • Start date
P

Pierre Barbier de Reuille

Hello there !

I was trying to code a scriptable MUD client (following the RubyQuiz
challenge). For the moment, I implemented a scriptable telnet which
works fine with my mail server and also with the test server provided by
James Edward Gray II on the RubyQuiz website. However, when I tried it
on a real MUD server, it just stopped receiving data after a few lines
(I tested it on imperian.com:23). The connection is not lost however, as
I can send commands (simple: if you can send "3", it will exit your
session :) ).

I join my code here, all the connection stuff are in the two methods
"connect" and "idle" of the MUD class.

Thanks,

Pierre

Code :


======8<============8<===========8<===========8<============8<=========
#!/usr/bin/ruby -w

require "socket"

class MUD

attr_reader :url, :port, :prefix, :io

attr_reader :commands, :answers

def initialize(url, port)
@url = url
@port = port
@answers = MUDFilters.new
@commands = MUDFilters.new
@prefix = "!"
@io = MUD::Io.new
register_defaults
end

def connect
@io.send ||= lambda { |line| @io.server_socket.write line }
@io.report ||= lambda { |line| $stdout.write line }
@socket = TCPSocket.new(@url, @port)
@io.report["Connected to #{@url}:#{@port}\n"]
@io.server_socket = @socket
@io.freeze
@url.freeze
@prefix.freeze
@thread = Thread.new do
idle
end
end

def disconnect
@io.server_socket.close unless @io.server_socket.closed?
@thread.join
puts "Disconnected ..."
end

def idle
f = File.new("log_server", "wb")
begin
while line = @io.server_socket.gets
f.write line
process_answer line
end
rescue
end
@io.server_socket.close unless @io.server_socket.closed?
return 0
end

def process_command(line)
process(@commands, line)
end

alias_method :send, :process_command

def process_answer(line)
process(@answers, line)
end

def add_command(regexp=//, priority=0, &block)
register(@commands, Rule.new(regexp, priority, &block))
end

def remove_command(id)
unregister(@commands, id)
end

def add_answer(regexp=//, priority=0, &block)
register(@answers, Rule.new(regexp, priority, &block))
end

def remove_answer(id)
unregister(@answers, id)
end

protected

def register_defaults
# Echo the server commands if nothing else
add_answer do |io,line|
io.report[line]
end
# Send the commands to the server
add_command do |io,line|
io.send[line]
end
# Load a new definition file
add_command(/^#{@prefix}load/i, 10000) do |io,line|
if line =~ /^#{@prefix}load (.*)$/i
config = $1
if config and FileTest.exists? config and FileTest.readable?(config)
io.report["Loading file #{config} ...\n"]
load(config,true)
end
end
nil
end
end

def process(filters,line)
selected = []
filters.each do |regexp, rules|
if line =~ regexp
selected += rules
end
end
selected.sort!
selected.each do |rule|
#puts "Launching rule #{rule.regexp.inspect} with priority
#{rule.priority}"
line = rule.block[@io,line]
if line == nil
return
end
end
end

def register(filters, rule)
filters[rule.regexp] << rule
filters.ids[rule.object_id] = rule.regexp
rule.object_id
end

def unregister(filters, id)
regexp = filters.ids[id]
filters[regexp].delete_if do |rule|
rule.object_id == id
end
end

class Rule
attr_accessor :priority, :block
attr_reader :regexp

def initialize(regexp, priority, &block)
@regexp = regexp
@priority = priority
@block = block
end

def <=>(other)
other.priority <=> @priority
end

end
class Io
attr_accessor :send, :report
attr_accessor :server_socket
end

class MUDFilters
attr_accessor :ids

include Enumerable

def initialize
@filters = Hash.new { |h,k| h[k] = [] }
@ids = Hash.new
end

def [](regexp)
@filters[regexp]
end

def []=(regexp, value)
@filters[regexp] = value
end

def each(&block)
@filters.each(&block)
end

end

end

if $0 == __FILE__
require "getoptlong"

opts = GetoptLong.new(
[ "--port", "-p", GetoptLong::OPTIONAL_ARGUMENT ],
[ "--config", "-c", GetoptLong::OPTIONAL_ARGUMENT ],
[ "--prefix", GetoptLong::OPTIONAL_ARGUMENT],
[ "--prompt", GetoptLong::OPTIONAL_ARGUMENT]
)

config = nil
port = 23
prefix = "!"

opts.each do |opt, arg|
case opt
when "--port"
port = arg.to_i
when "--config"
config = arg
when "--prefix"
prefix = Regexp.escape arg
end
end


if ARGV.length != 1
$stderr.write <<-EOF
Usage: #{$0} [--port PORT] [--config FILE] [--prefix PREFIX] [--] HOST
PORT port of the host to connect (default: #{port.to_s})
FILE ruby file imported with a main function called with the
MUD object (default:none)
HOST host to connect
PREFIX prefix for local commands (default:#{prefix})
EOF
exit 2
end

host = ARGV[0]

$mud = MUD.new(host, port)
$mud.prefix.replace(prefix)

if config and FileTest.exists? config and FileTest.readable? config
load(config,true)
end

$mud.connect

begin
loop do
line = $stdin.readline
$mud.send line
end
rescue EOFError
$mud.disconnect
end
end
======>8============>8===========>8===========>8============>8=========
 
R

Robert Klemme

Pierre said:
Hello there !

I was trying to code a scriptable MUD client (following the RubyQuiz
challenge). For the moment, I implemented a scriptable telnet which
works fine with my mail server and also with the test server provided
by James Edward Gray II on the RubyQuiz website. However, when I
tried it
on a real MUD server, it just stopped receiving data after a few lines
(I tested it on imperian.com:23). The connection is not lost however,
as
I can send commands (simple: if you can send "3", it will exit your
session :) ).

I join my code here, all the connection stuff are in the two methods
"connect" and "idle" of the MUD class.

The first changes I'd do are to use the block form of File.open, use
synchronized IO during testing and print out any exceptions you catch in
#idle. At the moment the script silently terminates if there is an
exception with socket io and you never learn what went wrong (timeout for
example).

Regards

robert
 
P

Pierre Barbier de Reuille

Robert Klemme a écrit :
The first changes I'd do are to use the block form of File.open, use
synchronized IO during testing and print out any exceptions you catch in
#idle. At the moment the script silently terminates if there is an
exception with socket io and you never learn what went wrong (timeout for
example).

Regards

robert

Well, thanks a lot, I found the error :) And, of course it was not were
I thought it was, and it was hidden by this bad exception handling ;)

Pierre
 

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

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,190
Members
46,740
Latest member
AdolphBig6

Latest Threads

Top