shogi-server source
修订版 | e37932a0d2387227928808ec86f49362ae29f9ea (tree) |
---|---|
时间 | 2020-10-02 01:36:08 |
作者 | Mizar <mizar.jp@gmai...> |
Commiter | Mizar |
tcp_keepalive
@@ -28,6 +28,7 @@ $:.unshift(File.join(File.dirname(File.expand_path(__FILE__)), "..")) | ||
28 | 28 | require 'shogi_server' |
29 | 29 | require 'logger' |
30 | 30 | require 'socket' |
31 | +require 'timeout' | |
31 | 32 | |
32 | 33 | # Global variables |
33 | 34 |
@@ -105,7 +106,12 @@ def parse_command_line | ||
105 | 106 | ["--options", GetoptLong::REQUIRED_ARGUMENT], |
106 | 107 | ["--password", GetoptLong::REQUIRED_ARGUMENT], |
107 | 108 | ["--ponder", GetoptLong::NO_ARGUMENT], |
108 | - ["--port", GetoptLong::REQUIRED_ARGUMENT]) | |
109 | + ["--port", GetoptLong::REQUIRED_ARGUMENT], | |
110 | + ["--ignoremultiselect", GetoptLong::NO_ARGUMENT], | |
111 | + ["--tcpkeepalive", GetoptLong::REQUIRED_ARGUMENT], | |
112 | + ["--tcpkeepalive-idle", GetoptLong::REQUIRED_ARGUMENT], | |
113 | + ["--tcpkeepalive-intvl", GetoptLong::REQUIRED_ARGUMENT], | |
114 | + ["--tcpkeepalive-cnt", GetoptLong::REQUIRED_ARGUMENT]) | |
109 | 115 | parser.quiet = true |
110 | 116 | begin |
111 | 117 | parser.each_option do |name, arg| |
@@ -132,6 +138,15 @@ def parse_command_line | ||
132 | 138 | options[:ponder] ||= ENV["PONDER"] || false |
133 | 139 | options[:port] ||= ENV["PORT"] || 4081 |
134 | 140 | options[:port] = options[:port].to_i |
141 | + options[:ignoremultiselect] ||= ENV["IGNORE_MULTISELECT"] || false | |
142 | + options[:tcpkeepalive] ||= ENV["TCPKEEPALIVE"] || 0 | |
143 | + options[:tcpkeepalive] = options[:tcpkeepalive].to_i | |
144 | + options[:tcpkeepalive_idle] ||= ENV["TCPKEEPALIVE_IDLE"] || 50 | |
145 | + options[:tcpkeepalive_idle] = options[:tcpkeepalive_idle].to_i | |
146 | + options[:tcpkeepalive_intvl] ||= ENV["TCPKEEPALIVE_INTVL"] || 5 | |
147 | + options[:tcpkeepalive_intvl] = options[:tcpkeepalive_intvl].to_i | |
148 | + options[:tcpkeepalive_cnt] ||= ENV["TCPKEEPALIVE_CNT"] || 9 | |
149 | + options[:tcpkeepalive_cnt] = options[:tcpkeepalive_cnt].to_i | |
135 | 150 | |
136 | 151 | return options |
137 | 152 | end |
@@ -424,7 +439,14 @@ class BridgeState | ||
424 | 439 | throw "Bad state at event_engine_recv: #@state" |
425 | 440 | end |
426 | 441 | |
427 | - str = $server.gets | |
442 | + str = nil | |
443 | + begin | |
444 | + Timeout.timeout(0.001){ | |
445 | + str = $server.gets | |
446 | + } | |
447 | + rescue Timeout::Error | |
448 | + $logger.error "event_server_recv timeout" | |
449 | + end | |
428 | 450 | return if str.nil? || str.strip.empty? |
429 | 451 | log_server_recv str |
430 | 452 |
@@ -567,6 +589,30 @@ def login | ||
567 | 589 | begin |
568 | 590 | $server = TCPSocket.open($options[:host], $options[:port]) |
569 | 591 | $server.sync = true |
592 | + if $options[:tcpkeepalive] > 0 && | |
593 | + Socket.const_defined?(:SOL_SOCKET) && | |
594 | + Socket.const_defined?(:SO_KEEPALIVE) && | |
595 | + Socket.const_defined?(:IPPROTO_TCP) | |
596 | + $server.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true) | |
597 | + if Socket.const_defined?(:TCP_KEEPIDLE) && | |
598 | + Socket.const_defined?(:TCP_KEEPINTVL) && | |
599 | + Socket.const_defined?(:TCP_KEEPCNT) | |
600 | + $server.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_KEEPIDLE, $options[:tcpkeepalive_idle]) | |
601 | + $server.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_KEEPINTVL, $options[:tcpkeepalive_intvl]) | |
602 | + $server.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_KEEPCNT, $options[:tcpkeepalive_cnt]) | |
603 | + elsif RUBY_PLATFORM.downcase =~ /mswin|mingw|cygwin|bccwin/ | |
604 | + # Windows 10 (1709 or later) ws2ipdef.h | |
605 | + # https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-tcp-socket-options | |
606 | + $server.setsockopt(Socket::IPPROTO_TCP, 3, $options[:tcpkeepalive_idle]) | |
607 | + $server.setsockopt(Socket::IPPROTO_TCP, 17, $options[:tcpkeepalive_intvl]) | |
608 | + $server.setsockopt(Socket::IPPROTO_TCP, 16, $options[:tcpkeepalive_cnt]) | |
609 | + elsif RUBY_PLATFORM.downcase =~ /darwin/ | |
610 | + # macOS 10.12.6 (Sierra) /usr/include/netinet/tcp.h | |
611 | + $server.setsockopt(Socket::IPPROTO_TCP, 0x10, $options[:tcpkeepalive_idle]) | |
612 | + $server.setsockopt(Socket::IPPROTO_TCP, 0x101, $options[:tcpkeepalive_intvl]) | |
613 | + $server.setsockopt(Socket::IPPROTO_TCP, 0x102, $options[:tcpkeepalive_cnt]) | |
614 | + end | |
615 | + end | |
570 | 616 | rescue |
571 | 617 | log_error "Failed to connect to the server" |
572 | 618 | $server = nil |
@@ -611,7 +657,7 @@ end | ||
611 | 657 | # |
612 | 658 | def main_loop |
613 | 659 | while true |
614 | - ret, = select([$server, $engine], nil, nil, 60) | |
660 | + ret, = select([$engine, $server], nil, nil, 60) | |
615 | 661 | unless ret |
616 | 662 | # Send keep-alive |
617 | 663 | if $bridge_state.too_quiet? |
@@ -621,12 +667,14 @@ def main_loop | ||
621 | 667 | next |
622 | 668 | end |
623 | 669 | |
624 | - ret.each do |io| | |
625 | - case io | |
626 | - when $engine | |
627 | - $bridge_state.do_engine_recv | |
628 | - when $server | |
629 | - $bridge_state.do_sever_recv | |
670 | + ret.each_with_index do |io, idx| | |
671 | + if (!$options[:ignoremultiselect] || idx == 0) | |
672 | + case io | |
673 | + when $engine | |
674 | + $bridge_state.do_engine_recv | |
675 | + when $server | |
676 | + $bridge_state.do_sever_recv | |
677 | + end | |
630 | 678 | end |
631 | 679 | end |
632 | 680 |
@@ -228,7 +228,10 @@ def parse_command_line | ||
228 | 228 | ["--max-identifier", GetoptLong::REQUIRED_ARGUMENT], |
229 | 229 | ["--max-moves", GetoptLong::REQUIRED_ARGUMENT], |
230 | 230 | ["--pid-file", GetoptLong::REQUIRED_ARGUMENT], |
231 | - ["--player-log-dir", GetoptLong::REQUIRED_ARGUMENT]) | |
231 | + ["--player-log-dir", GetoptLong::REQUIRED_ARGUMENT], | |
232 | + ["--tcpkeepalive-idle", GetoptLong::REQUIRED_ARGUMENT], | |
233 | + ["--tcpkeepalive-intvl", GetoptLong::REQUIRED_ARGUMENT], | |
234 | + ["--tcpkeepalive-cnt", GetoptLong::REQUIRED_ARGUMENT]) | |
232 | 235 | parser.quiet = true |
233 | 236 | begin |
234 | 237 | parser.each_option do |name, arg| |
@@ -308,6 +311,15 @@ def check_command_line | ||
308 | 311 | |
309 | 312 | $options["least-time-per-move"] ||= ShogiServer::Default_Least_Time_Per_Move |
310 | 313 | $options["least-time-per-move"] = $options["least-time-per-move"].to_i |
314 | + | |
315 | + $options["tcpkeepalive-idle"] ||= ShogiServer::Default_TcpKeepAlive_Idle | |
316 | + $options["tcpkeepalive-idle"] = $options["tcpkeepalive-idle"].to_i | |
317 | + | |
318 | + $options["tcpkeepalive-intvl"] ||= ShogiServer::Default_TcpKeepAlive_Intvl | |
319 | + $options["tcpkeepalive-intvl"] = $options["tcpkeepalive-intvl"].to_i | |
320 | + | |
321 | + $options["tcpkeepalive-cnt"] ||= ShogiServer::Default_TcpKeepAlive_Cnt | |
322 | + $options["tcpkeepalive-cnt"] = $options["tcpkeepalive-cnt"].to_i | |
311 | 323 | end |
312 | 324 | |
313 | 325 | # See if a file can be created in the directory. |
@@ -489,8 +501,30 @@ def main | ||
489 | 501 | server.start do |client| |
490 | 502 | begin |
491 | 503 | # client.sync = true # this is already set in WEBrick |
492 | - client.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true) | |
493 | - # Keepalive time can be set by /proc/sys/net/ipv4/tcp_keepalive_time | |
504 | + if Socket.const_defined?(:SOL_SOCKET) && | |
505 | + Socket.const_defined?(:SO_KEEPALIVE) && | |
506 | + Socket.const_defined?(:IPPROTO_TCP) | |
507 | + client.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true) | |
508 | + # Keepalive time can be set by /proc/sys/net/ipv4/tcp_keepalive_time | |
509 | + if Socket.const_defined?(:TCP_KEEPIDLE) && | |
510 | + Socket.const_defined?(:TCP_KEEPINTVL) && | |
511 | + Socket.const_defined?(:TCP_KEEPCNT) | |
512 | + client.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_KEEPIDLE, $options["tcpkeepalive-idle"]) | |
513 | + client.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_KEEPINTVL, $options["tcpkeepalive-intvl"]) | |
514 | + client.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_KEEPCNT, $options["tcpkeepalive-cnt"]) | |
515 | + elsif RUBY_PLATFORM.downcase =~ /mswin|mingw|cygwin|bccwin/ | |
516 | + # Windows 10 (1709 or later) ws2ipdef.h | |
517 | + # https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-tcp-socket-options | |
518 | + client.setsockopt(Socket::IPPROTO_TCP, 3, $options["tcpkeepalive-idle"]) | |
519 | + client.setsockopt(Socket::IPPROTO_TCP, 17, $options["tcpkeepalive-intvl"]) | |
520 | + client.setsockopt(Socket::IPPROTO_TCP, 16, $options["tcpkeepalive-cnt"]) | |
521 | + elsif RUBY_PLATFORM.downcase =~ /darwin/ | |
522 | + # macOS 10.12.6 (Sierra) /usr/include/netinet/tcp.h | |
523 | + client.setsockopt(Socket::IPPROTO_TCP, 0x10, $options["tcpkeepalive-idle"]) | |
524 | + client.setsockopt(Socket::IPPROTO_TCP, 0x101, $options["tcpkeepalive-intvl"]) | |
525 | + client.setsockopt(Socket::IPPROTO_TCP, 0x102, $options["tcpkeepalive-cnt"]) | |
526 | + end | |
527 | + end | |
494 | 528 | player, login = login_loop(client) # loop |
495 | 529 | unless player |
496 | 530 | log_error("Detected a timed out login attempt") |
@@ -51,6 +51,9 @@ Default_Timeout = 60 # for single socket operation | ||
51 | 51 | Default_Game_Name = "default-1500-0" |
52 | 52 | Default_Max_Moves = 256 |
53 | 53 | Default_Least_Time_Per_Move = 0 |
54 | +Default_TcpKeepAlive_Idle = 50 | |
55 | +Default_TcpKeepAlive_Intvl = 5 | |
56 | +Default_TcpKeepAlive_Cnt = 9 | |
54 | 57 | One_Time = 10 |
55 | 58 | Login_Time = 300 # time for LOGIN |
56 | 59 | Revision = "20180825" |