diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..36fe745
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+pkg/
+._*
+*~
+.DS_Store
+.*.swp
+*.log
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..fa75df1
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,3 @@
+source 'https://rubygems.org'
+
+gemspec
diff --git a/README.markdown b/README.markdown
index 04e6bc0..bd5f37a 100644
--- a/README.markdown
+++ b/README.markdown
@@ -48,8 +48,8 @@ faster than TCP, but you will not know if the server is down or encountered an
 error. You can specify what transport to use by selecting a subclient:
 
 ``` ruby
-c.udp << { :state "ok" } # => nil
-c.tcp << { :state "ok" } # => #<Message ...>
+c.udp << { :state => "ok" } # => nil
+c.tcp << { :state => "ok" } # => #<Message ...>
 c.tcp["true"]            # => [#<Event ... >, ...]
 c.udp["true"]            # => raise Riemann::Client::Unsupported
 ```
diff --git a/Rakefile.rb b/Rakefile.rb
new file mode 100644
index 0000000..79282c0
--- /dev/null
+++ b/Rakefile.rb
@@ -0,0 +1,46 @@
+$:.unshift(File.join(File.dirname(__FILE__), 'lib'))
+
+require 'rubygems'
+require 'rubygems/package_task'
+require 'rdoc/task'
+require 'riemann/version'
+require 'find'
+ 
+# Don't include resource forks in tarballs on Mac OS X.
+ENV['COPY_EXTENDED_ATTRIBUTES_DISABLE'] = 'true'
+ENV['COPYFILE_DISABLE'] = 'true'
+ 
+# Gemspec
+gemspec = Gem::Specification.new do |s|
+  s.rubyforge_project = 'riemann-client'
+ 
+  s.name = 'riemann-client'
+  s.version = Riemann::VERSION
+  s.author = 'Kyle Kingsbury'
+  s.email = 'aphyr@aphyr.com'
+  s.homepage = 'https://github.com/aphyr/riemann-ruby-client'
+  s.platform = Gem::Platform::RUBY
+  s.summary = 'Client for the distributed event system Riemann.'
+
+  s.add_dependency 'beefcake', '>= 0.3.5' 
+  s.add_dependency 'trollop', '>= 1.16.2'
+  s.add_dependency 'mtrc', '>= 0.0.4'
+   
+  s.files = FileList['{lib}/**/*', 'LICENSE', 'README.markdown'].to_a
+  s.executables = []
+  s.require_path = 'lib'
+  s.has_rdoc = true
+ 
+  s.required_ruby_version = '>= 1.8.7'
+end
+
+Gem::PackageTask.new gemspec do |p|
+end
+ 
+RDoc::Task.new do |rd|
+  rd.main = 'Riemann'
+  rd.title = 'Riemann'
+  rd.rdoc_dir = 'doc'
+ 
+  rd.rdoc_files.include('lib/**/*.rb')
+end
diff --git a/debian/changelog b/debian/changelog
index 65ed783..973b748 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,4 @@
-ruby-riemann-client (0.2.3-2) UNRELEASED; urgency=medium
+ruby-riemann-client (0.2.6-1) UNRELEASED; urgency=medium
 
   [ Cédric Boutillier ]
   * Bump debhelper compatibility level to 9
@@ -17,8 +17,9 @@ ruby-riemann-client (0.2.3-2) UNRELEASED; urgency=medium
   * Set upstream metadata fields: Bug-Database, Bug-Submit.
   * Update Vcs-* headers from URL redirect.
   * Use canonical URL in Vcs-Git.
+  * New upstream release.
 
- -- Utkarsh Gupta <guptautkarsh2102@gmail.com>  Tue, 13 Aug 2019 07:11:55 +0530
+ -- Utkarsh Gupta <guptautkarsh2102@gmail.com>  Thu, 17 Mar 2022 00:24:40 -0000
 
 ruby-riemann-client (0.2.3-1) unstable; urgency=medium
 
diff --git a/lib/riemann/client.rb b/lib/riemann/client.rb
index 32df850..f86f537 100644
--- a/lib/riemann/client.rb
+++ b/lib/riemann/client.rb
@@ -28,6 +28,13 @@ class Riemann::Client
 
     @udp = UDP.new(@options)
     @tcp = TCP.new(@options)
+    if block_given?
+      begin
+        yield self
+      ensure
+        close
+      end
+    end
   end
 
   def host
@@ -70,18 +77,17 @@ class Riemann::Client
       (response.states || [])
   end
 
+  def connect
+    # NOTE: connections are made automatically on send
+    warn "Riemann client#connect is deprecated"
+  end
+
   # Close both UDP and TCP sockets.
   def close
     @udp.close
     @tcp.close
   end
 
-  # Connect both UDP and TCP sockets.
-  def connect
-    udp.connect
-    tcp.connect
-  end
-
   def connected?
     tcp.connected? and udp.connected?
   end
diff --git a/lib/riemann/client/tcp.rb b/lib/riemann/client/tcp.rb
index d99e99b..bfcf1ca 100644
--- a/lib/riemann/client/tcp.rb
+++ b/lib/riemann/client/tcp.rb
@@ -28,9 +28,7 @@ module Riemann
             close
           end
 
-          if @socket and not @socket.closed?
-            return @socket
-          end
+          return @socket if connected?
 
           @socket = self.class.socket_factory.call(@options)
           @pid    = Process.pid
@@ -41,15 +39,15 @@ module Riemann
 
       def close
         @locket.synchronize do
-          if @socket && !@socket.closed?
-            @socket.close
-          end
+          @socket.close if connected?
           @socket = nil
         end
       end
 
       def connected?
-        !@socket && @socket.closed?
+        @locket.synchronize do
+          !@socket.nil? && !@socket.closed?
+        end
       end
 
       # Read a message from a stream
@@ -63,12 +61,12 @@ module Riemann
             puts "Message was #{str.inspect}"
             raise
           end
-          
+
           unless message.ok
             puts "Failed"
             raise ServerError, message.error
           end
-          
+
           message
         else
           raise InvalidResponse, "unexpected EOF"
@@ -87,7 +85,7 @@ module Riemann
       # Yields a connection in the block.
       def with_connection
         tries = 0
-        
+
         @locket.synchronize do
           begin
             tries += 1
diff --git a/lib/riemann/client/tcp_socket.rb b/lib/riemann/client/tcp_socket.rb
index 91a297e..102da71 100644
--- a/lib/riemann/client/tcp_socket.rb
+++ b/lib/riemann/client/tcp_socket.rb
@@ -115,8 +115,9 @@ module Riemann
         sock = ::Socket.new(::Socket::AF_INET, ::Socket::SOCK_STREAM, 0)
 
         # close file descriptors if we exec
-        sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
-
+        if Fcntl.constants.include?(:F_SETFD) && Fcntl.constants.include?(:FD_CLOEXEC)
+          sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
+        end
         # Disable Nagle's algorithm
         sock.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
 
@@ -331,4 +332,4 @@ module Riemann
       end
     end
   end
-end
\ No newline at end of file
+end
diff --git a/lib/riemann/client/udp.rb b/lib/riemann/client/udp.rb
index 0363133..73e3f42 100644
--- a/lib/riemann/client/udp.rb
+++ b/lib/riemann/client/udp.rb
@@ -3,27 +3,26 @@ module Riemann
     class UDP < Client
       MAX_SIZE = 16384
 
-      attr_accessor :host, :port, :socket, :max_size
+      attr_accessor :host, :port, :max_size
 
       def initialize(opts = {})
-        @host = opts[:host] || HOST
-        @port = opts[:port] || PORT
+        @host     = opts[:host] || HOST
+        @port     = opts[:port] || PORT
         @max_size = opts[:max_size] || MAX_SIZE
-        @locket = Mutex.new
       end
 
-      def connect
+      def socket
+        return @socket if connected?
         @socket = UDPSocket.new
       end
 
       def close
-        @locket.synchronize do
-          @socket.close
-        end
+        @socket.close if connected?
+        @socket = nil
       end
 
       def connected?
-        !!@socket && @socket.closed?
+        @socket && !@socket.closed?
       end
 
       # Read a message from a stream
@@ -36,42 +35,10 @@ module Riemann
       end
 
       def send_maybe_recv(message)
-        with_connection do |s|
-          x = message.encode ''
-          unless x.length < @max_size
-            raise TooBig
-          end
-
-          s.send(x, 0, @host, @port)
-          nil
-        end
-      end
-
-      # Yields a connection in the block.
-      def with_connection
-        tries = 0
-        
-        @locket.synchronize do
-          begin
-            tries += 1
-              yield(@socket || connect)
-          rescue IOError => e
-            raise if tries > 3
-            connect and retry
-          rescue Errno::EPIPE => e
-            raise if tries > 3
-            connect and retry
-          rescue Errno::ECONNREFUSED => e
-            raise if tries > 3
-            connect and retry
-          rescue Errno::ECONNRESET => e
-            raise if tries > 3
-            connect and retry
-          rescue InvalidResponse => e
-            raise if tries > 3
-            connect and retry
-          end
-        end
+        encoded_string = message.encode.to_s
+        raise TooBig unless encoded_string.length < @max_size
+        socket.send(encoded_string, 0, @host, @port)
+        nil
       end
     end
   end
diff --git a/lib/riemann/message.rb b/lib/riemann/message.rb
index 66bb93e..a2bd01f 100644
--- a/lib/riemann/message.rb
+++ b/lib/riemann/message.rb
@@ -1,7 +1,7 @@
 module Riemann
   class Message
     include Beefcake::Message
-    
+
     optional :ok, :bool, 2
     optional :error, :string, 3
     repeated :states, State, 4
@@ -9,9 +9,8 @@ module Riemann
     repeated :events, Event, 6
 
     def encode_with_length
-      buffer = ''
-      encoded = encode buffer
-      "#{[encoded.length].pack('N')}#{encoded}"
+      encoded_string = encode.to_s
+      [encoded_string.length].pack('N') << encoded_string
     end
-  end 
+  end
 end
diff --git a/lib/riemann/version.rb b/lib/riemann/version.rb
index 0cc76ea..466ed65 100644
--- a/lib/riemann/version.rb
+++ b/lib/riemann/version.rb
@@ -1,3 +1,3 @@
 module Riemann
-  VERSION = '0.2.3'
+  VERSION = '0.2.6'
 end
diff --git a/metadata.yml b/metadata.yml
deleted file mode 100644
index 09afea4..0000000
--- a/metadata.yml
+++ /dev/null
@@ -1,99 +0,0 @@
---- !ruby/object:Gem::Specification
-name: riemann-client
-version: !ruby/object:Gem::Version
-  version: 0.2.3
-platform: ruby
-authors:
-- Kyle Kingsbury
-autorequire: 
-bindir: bin
-cert_chain: []
-date: 2014-04-30 00:00:00.000000000 Z
-dependencies:
-- !ruby/object:Gem::Dependency
-  name: beefcake
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - '>='
-      - !ruby/object:Gem::Version
-        version: 0.3.5
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - '>='
-      - !ruby/object:Gem::Version
-        version: 0.3.5
-- !ruby/object:Gem::Dependency
-  name: trollop
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - '>='
-      - !ruby/object:Gem::Version
-        version: 1.16.2
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - '>='
-      - !ruby/object:Gem::Version
-        version: 1.16.2
-- !ruby/object:Gem::Dependency
-  name: mtrc
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - '>='
-      - !ruby/object:Gem::Version
-        version: 0.0.4
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - '>='
-      - !ruby/object:Gem::Version
-        version: 0.0.4
-description: 
-email: aphyr@aphyr.com
-executables: []
-extensions: []
-extra_rdoc_files: []
-files:
-- lib/riemann.rb
-- lib/riemann/attribute.rb
-- lib/riemann/auto_state.rb
-- lib/riemann/client.rb
-- lib/riemann/client/tcp.rb
-- lib/riemann/client/tcp_socket.rb
-- lib/riemann/client/udp.rb
-- lib/riemann/event.rb
-- lib/riemann/message.rb
-- lib/riemann/metric_thread.rb
-- lib/riemann/query.rb
-- lib/riemann/state.rb
-- lib/riemann/version.rb
-- LICENSE
-- README.markdown
-homepage: https://github.com/aphyr/riemann-ruby-client
-licenses: []
-metadata: {}
-post_install_message: 
-rdoc_options: []
-require_paths:
-- lib
-required_ruby_version: !ruby/object:Gem::Requirement
-  requirements:
-  - - '>='
-    - !ruby/object:Gem::Version
-      version: 1.8.7
-required_rubygems_version: !ruby/object:Gem::Requirement
-  requirements:
-  - - '>='
-    - !ruby/object:Gem::Version
-      version: '0'
-requirements: []
-rubyforge_project: riemann-client
-rubygems_version: 2.0.14
-signing_key: 
-specification_version: 4
-summary: Client for the distributed event system Riemann.
-test_files: []
diff --git a/riemann-client.gemspec b/riemann-client.gemspec
new file mode 100644
index 0000000..fe18787
--- /dev/null
+++ b/riemann-client.gemspec
@@ -0,0 +1,31 @@
+# coding: utf-8
+lib = File.expand_path('../lib', __FILE__)
+$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
+require 'riemann/version'
+
+Gem::Specification.new do |spec|
+  spec.name          = 'riemann-client'
+  spec.version       = Riemann::VERSION
+  spec.author        = 'Kyle Kingsbury'
+  spec.email         = 'aphyr@aphyr.com'
+  spec.summary       = 'Client for the distributed event system Riemann.'
+  spec.description   = 'Client for the distributed event system Riemann.'
+  spec.homepage      = 'https://github.com/aphyr/riemann-ruby-client'
+  spec.license       = 'MIT'
+  spec.platform      = Gem::Platform::RUBY
+
+  spec.files         = `git ls-files`.split($/)
+  spec.executables   = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
+  spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
+  spec.require_paths = ['lib']
+  spec.has_rdoc      = true
+
+  spec.required_ruby_version = '>= 1.8.7'
+
+  spec.add_development_dependency 'bundler', '>= 1.3'
+  spec.add_development_dependency 'bacon'
+
+  spec.add_dependency 'beefcake', ['>= 0.3.5','<= 1.0.0 ']
+  spec.add_dependency 'trollop', '>= 1.16.2'
+  spec.add_dependency 'mtrc', '>= 0.0.4'
+end
diff --git a/spec/client.rb b/spec/client.rb
new file mode 100755
index 0000000..8d16373
--- /dev/null
+++ b/spec/client.rb
@@ -0,0 +1,288 @@
+#!/usr/bin/env ruby
+
+# How to run the bacon tests:
+#   1. Start Riemann on default location 127.0.0.1:5555
+#   2. $ bundle exec bacon spec/client.rb
+
+require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'riemann'))
+require 'riemann/client'
+require 'bacon'
+require 'set'
+
+Bacon.summary_on_exit
+
+include Riemann
+
+INACTIVITY_TIME = 5
+RIEMANN_IP = ENV["RIEMANN_IP"] || "127.0.0.1"
+RIEMANN_PORT = ENV["RIEMANN_PORT"] || 5555
+
+def roundtrip_metric(m)
+  @client_with_transport << {
+    :service => 'metric-test',
+    :metric => m
+  }
+  @client["service = \"metric-test\" and metric = #{m}"].
+    first.metric.should.equal m
+end
+
+def truthy
+  lambda { |obj| !(obj.nil? || obj == false) }
+end
+
+def falsey
+  lambda { |obj| obj.nil? || obj == false }
+end
+
+shared "a riemann client" do
+
+  should 'yield itself to given block' do
+    client = nil
+    Client.new(:host => RIEMANN_IP, :port => RIEMANN_PORT) do |c|
+      client = c
+    end
+    client.should.be.kind_of?(Client)
+    client.should.not.be.connected
+  end
+
+  should 'close sockets if given a block that raises' do
+    client = nil
+    begin
+      Client.new(:host => RIEMANN_IP, :port => RIEMANN_PORT) do |c|
+        client = c
+        raise "The Boom"
+      end
+    rescue
+      # swallow the exception
+    end
+    client.should.be.kind_of?(Client)
+    client.should.not.be.connected
+  end
+
+  should 'be connected after sending' do
+    @client_with_transport.connected?.should.be falsey
+    @client.connected?.should.be falsey
+    @client_with_transport << {:state => 'ok', :service => 'connected check' }
+    @client_with_transport.connected?.should.be truthy
+    # NOTE: only single transport connected at this point, @client.connected? is still false until all transports used
+  end
+
+  should 'send longs' do
+    roundtrip_metric(0)
+    roundtrip_metric(-3)
+    roundtrip_metric(5)
+    roundtrip_metric(-(2**63))
+    roundtrip_metric(2**63 - 1)
+  end
+
+  should 'send doubles' do
+    roundtrip_metric 0.0
+    roundtrip_metric 12.0
+    roundtrip_metric 1.2300000190734863
+  end
+
+  should 'send custom attributes' do
+    event = Event.new(
+      :service => 'custom',
+      :state => 'ok',
+      :cats => 'meow',
+      :env => 'prod'
+    )
+    event[:sneak] = 'attack'
+    @client_with_transport << event
+    event2 = @client['service = "custom"'].first
+    event2.service.should.equal 'custom'
+    event2.state.should.equal 'ok'
+    event2[:cats].should.equal 'meow'
+    event2[:env].should.equal 'prod'
+    event2[:sneak].should.equal 'attack'
+  end
+
+  should 'send a state with a time' do
+    t = Time.now.to_i - 10
+    @client_with_transport << {
+      :state => 'ok',
+      :service => 'test',
+      :time => t
+    }
+    @client.query('service = "test"').events.first.time.should.equal t
+  end
+
+  should 'send a state without time' do
+    @client_with_transport << {
+      :state => 'ok',
+      :service => 'timeless test'
+    }
+    @client.query('service = "timeless test"').events.first.time.should.equal Time.now.to_i
+  end
+
+  should "query states" do
+    @client_with_transport << { :state => 'critical', :service => '1' }
+    @client_with_transport << { :state => 'warning', :service => '2' }
+    @client_with_transport << { :state => 'critical', :service => '3' }
+    @client.query.events.
+      map(&:service).to_set.should.superset ['1', '2', '3'].to_set
+    @client.query('state = "critical" and (service = "1" or service = "2" or service = "3")').events.
+      map(&:service).to_set.should.equal ['1', '3'].to_set
+  end
+
+  it '[]' do
+#    @client['state = "critical"'].should == []
+    @client_with_transport << {:state => 'critical'}
+    @client['state = "critical"'].first.state.should.equal 'critical'
+  end
+
+  should 'query quickly' do
+    t1 = Time.now
+    total = 1000
+    total.times do |i|
+      @client.query('state = "critical"')
+    end
+    t2 = Time.now
+
+    rate = total / (t2 - t1)
+    puts "\n     #{"%.2f" % rate} queries/sec (#{"%.2f" % (1000/rate)}ms per query)"
+    rate.should > 100
+  end
+
+  should 'be threadsafe' do
+    concurrency = 10
+    per_thread = 200
+    total = concurrency * per_thread
+
+    t1 = Time.now
+    (0...concurrency).map do |i|
+      Thread.new do
+        per_thread.times do
+          @client_with_transport.<<({
+            :state => 'ok',
+            :service => 'test',
+            :description => 'desc',
+            :metric_f => 1.0
+          })
+        end
+      end
+    end.each do |t|
+      t.join
+    end
+    t2 = Time.now
+
+    rate = total / (t2 - t1)
+    puts "\n     #{"%.2f" % rate} inserts/sec (#{"%.2f" % (1000/rate)}ms per insert)"
+    rate.should > @expected_rate
+  end
+
+end
+
+
+describe "Riemann::Client (TCP transport)" do
+  before do
+    @client = Client.new(:host => RIEMANN_IP, :port => RIEMANN_PORT)
+    @client_with_transport = @client.tcp
+    @expected_rate = 100
+  end
+  behaves_like "a riemann client"
+
+  should 'send a state' do
+    res = @client_with_transport << {
+      :state => 'ok',
+      :service => 'test',
+      :description => 'desc',
+      :metric_f => 1.0
+    }
+
+    res.ok.should.be truthy
+    @client['service = "test"'].first.state.should.equal 'ok'
+  end
+
+  should 'survive inactivity' do
+    @client_with_transport.<<({
+      :state => 'warning',
+      :service => 'survive TCP inactivity',
+    })
+    @client['service = "survive TCP inactivity"'].first.state.should.equal 'warning'
+
+    sleep INACTIVITY_TIME
+
+    @client_with_transport.<<({
+      :state => 'ok',
+      :service => 'survive TCP inactivity',
+    }).ok.should.be truthy
+    @client['service = "survive TCP inactivity"'].first.state.should.equal 'ok'
+  end
+
+  should 'survive local close' do
+    @client_with_transport.<<({
+      :state => 'warning',
+      :service => 'survive TCP local close',
+    }).ok.should.be truthy
+    @client['service = "survive TCP local close"'].first.state.should.equal 'warning'
+
+    @client.close
+
+    @client_with_transport.<<({
+      :state => 'ok',
+      :service => 'survive TCP local close',
+    }).ok.should.be truthy
+    @client['service = "survive TCP local close"'].first.state.should.equal 'ok'
+  end
+end
+
+describe "Riemann::Client (UDP transport)" do
+  before do
+    @client = Client.new(:host => RIEMANN_IP, :port => RIEMANN_PORT)
+    @client_with_transport = @client.udp
+    @expected_rate = 1000
+  end
+  behaves_like "a riemann client"
+
+  should 'send a state' do
+    res = @client_with_transport << {
+      :state => 'ok',
+      :service => 'test',
+      :description => 'desc',
+      :metric_f => 1.0
+    }
+
+    res.should.be.nil
+    @client['service = "test"'].first.state.should.equal 'ok'
+  end
+
+  should 'survive inactivity' do
+    @client_with_transport.<<({
+      :state => 'warning',
+      :service => 'survive UDP inactivity',
+    })
+    @client['service = "survive UDP inactivity"'].first.state.should.equal 'warning'
+
+    sleep INACTIVITY_TIME
+
+    @client_with_transport.<<({
+      :state => 'ok',
+      :service => 'survive UDP inactivity',
+    })
+    @client['service = "survive UDP inactivity"'].first.state.should.equal 'ok'
+  end
+
+  should 'survive local close' do
+    @client_with_transport.<<({
+      :state => 'warning',
+      :service => 'survive UDP local close',
+    })
+    @client['service = "survive UDP local close"'].first.state.should.equal 'warning'
+
+    @client.close
+
+    @client_with_transport.<<({
+      :state => 'ok',
+      :service => 'survive UDP local close',
+    })
+    @client['service = "survive UDP local close"'].first.state.should.equal 'ok'
+  end
+
+  should "raise Riemann::Client::Unsupported exception on query" do
+    should.raise(Riemann::Client::Unsupported) { @client_with_transport['service = "test"'] }
+    should.raise(Riemann::Client::Unsupported) { @client_with_transport.query('service = "test"') }
+  end
+
+end