forked from jiangmiao/proxy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
monitor.rb
176 lines (155 loc) · 3.45 KB
/
monitor.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# encoding: utf-8
require 'socket'
require 'btk'
include Gtk
INFO_ID = 0
INFO_ADDRESS = 1
INFO_ACTIVED_AT = 2
INFO_SENT = 3
INFO_RECV = 4
INFO_FIELDS_NUM = 5
COLS = ["序号", "地址", "活跃时间", "发送", "接收"]
COLS_NUM = COLS.size
mutex = Mutex.new
$infos_hash = {}
$sel = nil
FRONT_PORT = $ARGV[0] || 8780
def humanize(num)
num = num.to_i
[
[1e9, 'G'],
[1e6, 'M'],
[1e3, 'K'],
[1, 'B']
].each do|scale, unit|
if num >= scale
return (num/scale).round(1).to_s + unit
end
end
end
# \x99, \x00
def get_infos
s = nil
s = TCPSocket.new 'localhost', FRONT_PORT
s.send("\x99\x00", 0)
length = s.recv(4).unpack("i>")[0]
raw_infos = s.recv(length).split(",")
infos = []
i = 0
while true
info = raw_infos[i..i+INFO_FIELDS_NUM-1]
i += INFO_FIELDS_NUM
break unless info[INFO_ID]
next if info[INFO_ADDRESS] == ""
info[INFO_ID] = info[INFO_ID].to_i
info[INFO_RECV] = humanize(info[INFO_RECV])
info[INFO_SENT] = humanize(info[INFO_SENT])
infos << info
end
infos.sort! {|a, b|
a[INFO_ID] <=> b[INFO_ID]
}
now = Time.now.to_i
infos.map! {|info|
actived_at = (info[INFO_ACTIVED_AT].to_i/1e6).to_i
diff = now - actived_at
if diff < 60
actived_at_str = "#{diff} 秒前"
elsif diff < 3600
actived_at_str = "#{diff/60} 分钟前"
elsif
actived_at_str = Time.at(actived_at).strftime("%T")
end
info[INFO_ACTIVED_AT] = actived_at_str
info[INFO_ID] = info[INFO_ID].to_s
info
}
infos
ensure
s.close() if s
end
# \x98, \x00, PortNum:16, PortId:16 * PortNum
def close_ports(ids)
s = nil
data = ([ids.length] + ids).pack("S>*")
s = TCPSocket.new 'localhost', FRONT_PORT
s.send("\x98\x00", 0)
s.send(data, data.bytesize)
ensure
s.close() if s
end
Btk.Window :default_size=>[300, 300], :window_position=>Window::POS_CENTER do|w|
w.sig_destroy do
puts "done."
Gtk.main_quit
end
w.VBox do|vbox|
vbox.ScrolledWindow :policy=>[POLICY_AUTOMATIC, POLICY_AUTOMATIC] do|sw|
store = ListStore.new String, String, String, String, String
$store = store
sw.TreeView store do|tv|
COLS.each_index do|idx|
renderer = CellRendererText.new
if idx >= INFO_ACTIVED_AT
renderer.xalign=1.0
end
col = TreeViewColumn.new(COLS[idx], renderer, :text => idx)
col.resizable=true
tv.append_column(col)
end
tv.selection.mode=SELECTION_MULTIPLE
$sel = tv.selection
end
Thread.new do
iters = {}
while true
begin
mutex.synchronize do
$infos_hash = {}
infos = get_infos()
remove_list = Hash[iters.keys.zip]
infos.each {|info|
id = info[INFO_ID]
remove_list.delete(id)
iter = iters[id]
unless iter
iter = store.prepend
iters[id] = iter
end
COLS.each_index do |idx|
iter[idx] = info[idx]
end
$infos_hash[id] = info
}
for id in remove_list.keys
store.remove(iters[id])
iters.delete(id)
end
end
sleep 1
rescue
puts "#{$!.message.force_encoding("utf-8")}, 等待2秒"
# puts $@
sleep 2
end
end
end
end
vbox.HBox :pack=>false do|hbox|
hbox.Button "中断连接", :pack=>false do|btn|
btn.signal_connect 'clicked' do
mutex.synchronize do
ids = $sel.selected_rows.collect do|path|
iter = $store.get_iter(path)
id = iter[0]
$infos_hash[id][INFO_ID].to_i
end
close_ports(ids)
end
end
end
end
end
w.show_all
end
Gtk.main