多次向 TCPServer 发送数据

Sending data to TCPServer more than one time

我是 ruby 的新手,我正在尝试让客户端连接到 TCPServer,似乎为此我必须调用方法 close_write每次我用一种方式发送完数据,让client/server知道另一端发送完数据。每当我这样做时,我就无法再次将信息写入服务器或客户端,因为套接字不再打开以进行写入。 这是我的代码:

client.rb

需要“套接字”

套接字=TCPSocket.open("localhost", 6666)

loop do
  input = gets.chomp
  socket.puts input # Send data to server
  socket.close_write
  while(line = socket.gets)
    puts line
  end # Print sever response
  break if input=="EXIT"
end
socket.close

server.rb

require "socket"

server = TCPServer.new 6666
data = Hash.new { |hash, key| hash[key] = {} }

WAITING_SET_VALUE = "1"
WAITING_NEW_COMMAND = "0"

loop do

  Thread.start(server.accept) do |session|
    thread_status ||= WAITING_NEW_COMMAND
    ....

    puts "Entering If..."
    if(thread_status == WAITING_NEW_COMMAND) #Check thread status
      puts "thread_status == WAITING_NEW_COMMAND"
      puts "CHECKING COMMAND.."
      case line.strip
      when /^set \w* \w* \d{1,7} \d{1,7}$/
        puts "COMMAND SET"
        thread_status = WAITING_SET_VALUE
        lineArr = line.strip.split(" ")
        varName = lineArr[1]
        flag = lineArr[2]
        ttl = lineArr[3]
        size = lineArr[4]
        puts "END SET EXECUTION"
        session.write "Executed"
        session.close_write
      ...

有没有办法打开套接字再次写入,或者有更好的方法在服务器和客户端之间来回连接而不丢失上下文?谢谢!

在设计客户端-服务器协议时,您必须决定:

  • 客户端如何知道响应何时有更多 lines/data。
  • 客户端如何知道响应何时完成。
  • 客户端如何知道响应何时为 invalid/valid。
  • 客户端如何知道何时出现某种类型的服务器错误。

一个简单的方法是让服务器 return 一个包含行数的响应(如下面的代码)。但是,相反,您可以使用 END 或其他方式,以便客户端知道何时没有更多数据可读。我会强烈 建议查看有关协议的教程。

将以下内容保存到名为 client_server.rb 的文件中。首先,运行 服务器 ruby ./client_server.rb s,然后在单独的终端 运行 客户端 ruby ./client_server.rb c。接下来,一遍又一遍地输入 list 以查看不同的响应。我添加了 list,这样您就不必为了测试目的而一遍又一遍地输入 set w w 1 1。检查一下,如果您有任何问题,请告诉我。

# frozen_string_literal: true

require 'socket'


# Use:
#   First, run the server:  ruby ./client_server.rb s
#   Then, run the client:   ruby ./client_server.rb c

# Use "netcat localhost 6666" on the command line to test
# without implementing a client.


# Returns false to close this client socket.
# Returns true to continue reading from this client socket.
def handle_client(client_id, client_socket, command)

  # TODO: Define some type of client-server Protocol here.
  case command
  when /^set \w* \w* \d{1,7} \d{1,7}$/
    puts "Running command for client #{client_id}: #{command}"

    # This is just for testing purposes.
    case rand(3)
    when 0
      client_socket.puts 'lines 0'
    when 1
      client_socket.puts 'lines 3'
      client_socket.puts 'This is line 1.'
      client_socket.puts 'This is line 2.'
      client_socket.puts 'This is line 3.'
    when 2
      client_socket.puts 'The set command returned an error.'
    end
  when 'list'
    puts "Responding to client #{client_id} with list of messages."

    # This is just for testing purposes.
    case rand(3)
    when 0
      client_socket.puts 'messages 0'
    when 1
      client_socket.puts 'messages 2'
      client_socket.puts 'This is message 1.'
      client_socket.puts 'This is message 2.'
    when 2
      client_socket.puts 'Unable to retrieve messages due to error.'
    end
  when 'bye'
    puts "Killing client #{client_id}."

    return false # Disconnect and kill the thread.
  else
    client_socket.puts "[ERROR] Invalid command: #{command}"
  end

  client_socket.flush # Flush all output just in case.

  true # Continue connection.
end


case ARGV[0].to_s.downcase
when 's' # server
  TCPServer.open(6666) do |server_socket|
    global_client_id = 1

    loop do
      Thread.start(global_client_id, server_socket.accept) do |client_id, client_socket|
        puts "Accepting new client #{client_id}."

        loop do
          command = client_socket.gets

          if command.nil?
            puts "Client #{client_id} disconnected manually."
            break
          end

          command = command.strip
          keep_alive = handle_client(client_id, client_socket, command)

          break unless keep_alive
        end

        client_socket.close
      end

      global_client_id += 1
    end
  end
when 'c' # client
  TCPSocket.open('localhost', 6666) do |socket|
    puts '[Commands]'
    puts 'set <word> <word> <num> <num>    Run set command.'
    puts 'list                             Get list of messages.'
    puts 'exit, bye                        Exit the client.'
    puts

    loop do
      print '> '
      input = $stdin.gets.strip

      # TODO: Define some type of client-server Protocol here.
      case input
      when /EXIT|BYE/i
        socket.puts 'bye'
        socket.flush
        break
      when /\Aset .+\z/
        socket.puts input
        socket.flush

        response = socket.gets

        if response.nil?
          puts 'Server is not running anymore! Disconnecting.'
          break
        end

        response = response.strip
        match_data = response.match(/\Alines (?<lines>\d+)\z/)

        if match_data
          line_count = match_data[:lines].to_i

          puts "Received #{line_count} lines from server."

          1.upto(line_count) do |i|
            line = socket.gets

            puts ">> Resp[#{i}] #{line}"
          end
        else
          # Can check for "response == 'ERROR'" or something.
          puts "Server error or invalid response from server: #{response}"
        end
      when 'list'
        socket.puts input
        socket.flush

        response = socket.gets

        if response.nil?
          puts 'Server is not running anymore! Disconnecting.'
          break
        end

        response = response.strip
        match_data = response.match(/\Amessages (?<messages>\d+)\z/)

        if match_data
          message_count = match_data[:messages].to_i

          puts "Received #{message_count} messages from server."

          1.upto(message_count) do |i|
            line = socket.gets

            puts ">> Resp[#{i}] #{line}"
          end
        else
          # Can check for "response == 'ERROR'" or something.
          puts "Server error or invalid response from server: #{response}"
        end
      else
        puts "Invalid command: #{input}"
      end
    end
  end
else
  puts "Pass in 'c' for client or 's' for server."
end