# Client/server with threads

**URL:** <https://www.ruby-forum.com/t/client-server-with-threads/65592>\
**Category:** Ruby\
**Created:** [August 19, 2006, 3:56pm UTC](https://www.ruby-forum.com/t/client-server-with-threads/65592 "2006-08-19T15:56:53Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![unknown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/4bbf92/32.png) [@unknown](https://www.ruby-forum.com/u/unknown)\
**Post date:** [August 19, 2006, 3:56pm UTC](https://www.ruby-forum.com/t/client-server-with-threads/65592/1 "2006-08-19T15:56:53Z")

</div>

Yow!  
I’m trying to make a script that will act as a server (server 1), and  
when a connection to the server server 1 is made, it will start a  
thread that will connect to another server (server 2), and it will keep  
the connection to server 2, even if the client disconnects.

The thing is that, as I’ve tried, my client/server will not connect to  
another server, and if it does, the client can not disconnect.

Any ideas?

Thanks,  
Andreas

* * *

require ‘socket’

class Session \< Thread  
def initalize(session\_id)  
super  
@session\_id = session\_id  
end

def session\_id  
@session\_id  
end

def send\_message( message  
# This method should send a message to  
# server 2  
puts message  
end  
end

threads = []

server = TCPServer.new(“0.0.0.0”, 12121)

while (session = server.accept)  
session\_id, message = session.gets.split(";", 2)

t = threads.map {|t| t if t[“session\_id”] == session\_id }.delete\_if  
{|s| s == nil}.first  
puts t  
if t  
puts “Found thread with existing session\_id: #{ session\_id }”  
t.send :send\_message, message  
else  
threads \<\< Session.new(session) do |t|  
Thread.current[“session\_id”] = session\_id  
puts “Creating thread for #{ session\_id }”  
end  
end  
session.close  
end

---

<div class="post-metadata">

**Author:** ![unknown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/4bbf92/32.png) [@unknown](https://www.ruby-forum.com/u/unknown)\
**Post date:** [August 19, 2006, 4:02pm UTC](https://www.ruby-forum.com/t/client-server-with-threads/65592/2 "2006-08-19T16:02:53Z")

</div>

On 8/19/06, removed\_email\_address@domain.invalid [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> ```
> @session_id = session_id
> 
> ```
> 
> end  
> {|s| s == nil}.first  
> session.close  
> end

First, make sure your constructor is getting called. You spelled it  
“initalize” instead of “initialize”

---

<div class="post-metadata">

**Author:** ![unknown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/4bbf92/32.png) [@unknown](https://www.ruby-forum.com/u/unknown)\
**Post date:** [August 19, 2006, 5:39pm UTC](https://www.ruby-forum.com/t/client-server-with-threads/65592/3 "2006-08-19T17:39:05Z")

</div>

unknown wrote:

> Oh, thanks. 🙂 Didn’t see that. 🙂
> 
> But, now, there are some problems. The program gets stuck in the loop  
> on line 12, which I want the program to do in the background. (and it  
> shouldn’t get stuck) 🙂

Please forgive me, I don’t intend to be rude, but this program is not  
well thought out. You should reconsider your use of threads in the first  
place. Try an implementation with fork until you get it right. (And fork  
after you accept, not after you block on a gets from the accepted  
socket.)

I think your program gets “stuck” because you’re executing your loop in  
a subclassed constructor. The new thread of control that you think  
you’re getting never actually starts running. To prove it, put a print  
statement immediately after the accept, and then connect to your program  
twice, from two different shells. I predict the second client will  
appear to connect (because the TCP server picks it up in the kernel) but  
your accept call will not execute more than once.

---

<div class="post-metadata">

**Author:** ![unknown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/4bbf92/32.png) [@unknown](https://www.ruby-forum.com/u/unknown)\
**Post date:** [August 19, 2006, 6:31pm UTC](https://www.ruby-forum.com/t/client-server-with-threads/65592/4 "2006-08-19T18:31:13Z")

</div>

Francis C. wrote:

> place. Try an implementation with fork until you get it right. (And fork  
> after you accept, not after you block on a gets from the accepted  
> socket.)
> 
> I think your program gets “stuck” because you’re executing your loop in  
> a subclassed constructor. The new thread of control that you think  
> you’re getting never actually starts running. To prove it, put a print  
> statement immediately after the accept, and then connect to your program  
> twice, from two different shells. I predict the second client will  
> appear to connect (because the TCP server picks it up in the kernel) but  
> your accept call will not execute more than once.

Thanks for the advice, and for explaining 🙂  
I’ll take a look at fork and see if I can get this working 🙂

---

<div class="post-metadata">

**Author:** ![unknown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/4bbf92/32.png) [@unknown](https://www.ruby-forum.com/u/unknown)\
**Post date:** [August 19, 2006, 4:30pm UTC](https://www.ruby-forum.com/t/client-server-with-threads/65592/5 "2006-08-19T16:30:55Z")

</div>

Oh, thanks. 🙂 Didn’t see that. 🙂

But, now, there are some problems. The program gets stuck in the loop  
on line 12, which I want the program to do in the background. (and it  
shouldn’t get stuck) 🙂

require ‘socket’

class Session \< Thread  
def initialize(session)  
super  
puts session  
@session\_id, @nick, @channels = session.split(";", 3)  
@host = “wowow”  
@channels = @channels.split(",")  
@connected = 0  
@connection = TCPSocket.new(“127.0.0.1”, 12122)  
until @connection.closed?  
print “a”  
if @connected == 0  
login  
@connected = 1  
end  
raw = @connection.gets  
parse( raw.strip ) unless raw.nil?  
end  
end

def session\_id  
@session\_id  
end

def send\_message( message )  
puts message  
end

def irc\_join( channel )  
irc\_raw( “JOIN #{ channel }” )  
end

def irc\_nick( nick )  
irc\_raw( “NICK #{ nick }” )  
@nick = nick  
end

private

def irc\_raw( msg )  
@connection.send( “#{ msg }\r\n”, 0 )  
end

def login  
irc\_raw( “NICK #{ @nick }” )  
irc\_raw( "USER #{ @nick } #{ @nick } #{ @host } : #{ @nick } " )  
end

def parse( line )  
input = line.split(" ")  
if input[0][0].chr == “:”  
case input[1]  
when “001”  
@channels.each {|c| irc\_join© }  
when “433”  
irc\_nick( “#{ @nick }\_” )  
end  
end  
end

end

threads = []

server = TCPServer.new(“0.0.0.0”, 12121)

while (session = server.accept)  
session\_id, message = session.gets.split(";", 2)

t = threads.map {|t| t if t[“session\_id”] == session\_id }.delete\_if  
{|s| s == nil}.first  
puts t  
if t  
puts “Found thread with existing session\_id: #{session\_id}”  
t.send :send\_message, message  
else  
threads \<\< Session.new("#{session\_id};#{message}") do |t|  
Thread.current[“session\_id”] = session\_id  
puts “Creating thread for #{ session\_id }”  
end  
end  
session.close  
end
