简体   繁体   English

多次向 TCPServer 发送数据

[英]Sending data to TCPServer more than one time

I'm new to ruby and I'm trying to make a client to connect to a TCPServer, and it seems that in order to do so I have to call the method close_write every time I finish sending data one way, to let the client/server know that the other end is finished sending data.我是 ruby 的新手,我正在尝试让客户端连接到 TCPServer,似乎为了做到这一点,我每次完成以一种方式发送数据时都必须调用 close_write 方法,让客户端/server 知道另一端数据发送完毕。 Whenever I do that then Im not able to write info to the server or client again because the socket is not opened for writing anymore.每当我这样做时,我就无法再次将信息写入服务器或客户端,因为不再打开套接字进行写入。 This is my code:这是我的代码:

client.rb客户端.rb

require "socket"需要“插座”

socket = TCPSocket.open("localhost", 6666) socket = 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服务器.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
      ...

Is there a way to open the socket for writing again, or a better way to do this back and forth connection between server and client without losing context?有没有办法打开套接字再次写入,或者有更好的方法在服务器和客户端之间来回连接而不丢失上下文? Thanks!谢谢!

When designing a client-server protocol, you have to decide:在设计客户端-服务器协议时,您必须决定:

  • How a client knows when a response has more lines/data.客户端如何知道响应何时有更多行/数据。
  • How a client knows when a response is complete.客户端如何知道响应何时完成。
  • How a client knows when a response is invalid/valid.客户端如何知道响应何时无效/有效。
  • How a client knows when there was some type of server error.客户端如何知道何时出现某种类型的服务器错误。

A simple approach is for the server to return a response with the number of lines (as in the code below).一个简单的方法是让服务器返回带有行数的响应(如下面的代码所示)。 However, instead, you could use END or something so that the client knows when there is no more data to read.但是,相反,您可以使用END或其他东西,以便客户端知道何时没有更多数据要读取。 I would strongly suggest looking into tutorials about Protocols.强烈建议查看有关协议的教程。

Save the below into a file called client_server.rb .将以下内容保存到名为client_server.rb的文件中。 First, run the server with ruby./client_server.rb s and then in a separate terminal run the client with ruby./client_server.rb c .首先,使用ruby./client_server.rb s运行服务器,然后在单独的终端中使用ruby./client_server.rb c运行客户端。 Next, type in list over and over to see the different responses.接下来,一遍又一遍地输入list以查看不同的响应。 I added list so that you don't have to type in set ww 1 1 over and over for testing purposes.我添加了list ,这样您就不必为了测试目的而一遍又一遍地输入set ww 1 1 Check it out and let me know if you have any questions.检查一下,如果您有任何问题,请告诉我。

# 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM