Question about sockets/listeners

hi, i’m very new to ruby and so i’d be very grateful of any help on
this. I am writing a script that listens for UDP packets on a
particular port. This is very easy using ‘socket’. I then want to make
a script that simulates lots of clients sending UDP packets to the
listener. These clients should send a UDP packet from a particular port
and then listen for a response on that same port. For this reason, I am
trying to run each simulated client in a different thread. A simplified
version of what i have done so far is shown below, however, when I run
this, the client stops sending packets after the 66th one. Can someone
explain this to me please? why is it stopping at 66? which limit am i
hitting?

Also, any suggestions on how to improve the code will be gratefully
received. Thanks

Listener.rb

require “socket”

socket = UDPSocket.open
socket.bind("",1500)

while true
message, details = socket.recvfrom(512)
p message
end

Clients.rb

require ‘socket’

SERVER_IP = “127.0.0.1”
SERVER_PORT = 1500

packets=[]
threads =[]

Build an array of packets

for i in 1…100
packets << “packet#{i}”
end

For Packet to be sent, start a new thread

for packets_to_send in packets
sleep 0.1
threads << Thread.new(packets_to_send) do |packet|

#Generate a random port
port = rand(60000)

Open a socket on that port

socket = UDPSocket.open
socket.bind("",port)

Send the packet

puts “Sending #{packet}”
socket.send(packet, 0, SERVER_IP, SERVER_PORT)

while true
message, message_details = socket.recvfrom(512)
end

end
end

On Dec 15, 2007, at 9:38 AM, James C. wrote:

A simplified
version of what i have done so far is shown below, however, when I run
this, the client stops sending packets after the 66th one. Can
someone
explain this to me please? why is it stopping at 66? which limit
am i
hitting?

My first guess is that you are running out of file descriptors. It
looks like each thread creates a new socket, calls send, then calls
recvfrom repeatedly, never closing the socket and freeing the file
descriptor.

You should close the socket after receiving a response. Alternatively
you could see how to raise the per/process file descriptor limit for
your system (for bash, try looking at the ulimit command–the exact
command and syntax depends on the shell you are using).

Gary W.

On Dec 15, 2007, at 9:38 AM, James C. wrote:

why is it stopping at 66? which limit am i
hitting?

You main thread may be existing before all the
threads have been started.

After creating all the threads you need to wait
for them to finish by calling t.join on each one.

Gary W.

Gary W. wrote:

You should close the socket after receiving a response.

Sorry, I should have said, I am expecting mulitple responses from the
server and hence I want to keep the socket open.

Gary W. wrote:

You main thread may be existing before all the threads have been started.

The threads shouldn’t be exiting because I have the ‘while true’ in
there. I have just tried joining the threads and it didn’t fix it. It
might be the file descriptor thing, i’ll have to have a read up about
it. Thanks

On Dec 15, 2007 9:38 AM, James C. [email protected] wrote:

hitting?

Also, any suggestions on how to improve the code will be gratefully
received. Thanks

Using a nonthreaded approach, I got up to about 360 packets through on a
single run. (This program requires the Ruby/EventMachine library):

#-----------------------------------------
require ‘rubygems’
require ‘eventmachine’

EM.epoll

SERVER = “127.0.0.1”
PORT = 1500

module Server
def receive_data data
send_data “I saw your #{data}”
end
end

module Client
def post_init
@@counter ||= 0
@@counter += 1
send_datagram “Data packet #{@@counter}”, SERVER, PORT
end
def receive_data data
@@received ||= 0
@@received += 1
p “Received #{@@received}: #{data}”
end
end

EM.run {
EM.open_datagram_socket SERVER, PORT, Server
(60000…60400).each {|n|
EM.open_datagram_socket SERVER, n, Client
}
}

#-------------------------------

I did two things differently: first, I didn’t introduce a delay between
each
new socket. If I had, then this program would probably have scaled much
farther. And second, I used sequential port numbers rather than random
ones,
to avoid trying to open an already-open port, and to avoid trying to
open a
privileged one.

On Dec 15, 2007 9:38 AM, James C. [email protected] wrote:

hitting?

Ok, I tweaked my test program somewhat:

#---------------------------------------
require ‘rubygems’
require ‘eventmachine’

EM.epoll

SERVER = “127.0.0.1”
PORT = 1500

module Server
def receive_data data
send_data “I saw your #{data}”
end
end

module Client
def post_init
@@counter ||= 0
@@counter += 1
send_datagram “Data packet #{@@counter}”, SERVER, PORT
end
def receive_data data
@@received ||= 0
@@received += 1
p “Received #{@@received}: #{data}”
close_connection
end
end

EM.run {
EM.open_datagram_socket SERVER, PORT, Server

    t = EM::PeriodicTimer.new(0.05) {
            n = rand(1000) + 60000
            EM.open_datagram_socket SERVER, n, Client
    }

}

#-----------------------------

Now I’m delaying before opening each client as you were, and I’m using
random ports chosen in a high range. I’m also closing client sockets
after
they receive their responses. This version is now up to 10,000 packets
and
it’s still running strong.

Also, on a Linux kernel, I took out the close_connection statement and
used
EPOLL to eliminate Ruby’s limit of 1024 descriptors per process. I had
to
add a mechanism to keep the random port number generator from giving the
number of an already-open port. That program is also still running at
well
over 10,000 open sockets and packets now.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs