GTK+ とソケットを使ってチャット通信(Ruby)
Ruby/GTK2 の使い方が少しづつわかってきたので、ソケットを使ってチャット通信ソフトを作ってみました。上の例では Linux Mint 18.3 と Ubuntu Budgie を使って実行しています。
まずはサーバ側を立ち上げます。これはふつうに
$ ruby oshaberi.rb
と実行するだけです。次にクライアント側では、localhost や サーバの IPアドレスを指定して
$ ruby oshaberi.rb 192.168.11.7
みたいな感じで立ち上げます。もちろんインターネットに出てはいけません。LAN 内で遊んで下さい。
次に名前を訊いてくるので入れて下さい。
あとは上のエントリーバーから文字を入力すると、自分と相手側のスクロール・ウィンドウに会話の文字が表示されます。というように、簡単でしょう?
コードです。
oshaberi.rb
require 'gtk2' require 'socket' module Oshaberi class MyWindow < Gtk::Window def initialize super("Oshaberi") set_resizable(true) set_size_request(500, 300) entry = Gtk::Entry.new entry.set_editable(true) entry.set_height_request(40) entry.modify_font(Pango::FontDescription.new("13")) tv = Gtk::TextView.new tv.modify_font(Pango::FontDescription.new("12")) tv.set_editable(false) tv.set_cursor_visible(false) buf = tv.buffer sock1, sock2 = ARGV[0] ? client(ARGV[0]) : server sock1.set_encoding('UTF-8') sock2.set_encoding('ASCII-8BIT') myname, hisname = get_names(sock1, sock2) entry.signal_connect('activate') do st = entry.text buf.insert_interactive(buf.end_iter, myname + ": " + st + "\n", true) tv.scroll_mark_onscreen(buf.create_mark(nil, buf.end_iter, true)) entry.set_text("") sock2.puts st end sw = Gtk::ScrolledWindow.new sw.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC) sw.add(tv) box = Gtk::VBox.new add(box) box.pack_start(entry, false, true, 0) box.pack_start(sw , true , true, 0) Thread.new(sock1, tv, buf, hisname) do |sock, tv, buf, name| ioc = GLib::IOChannel.new(sock) ioc.add_watch(GLib::IOChannel::IN) do |i| buf.insert_interactive(buf.end_iter, name + ": " + (i.gets || exit), true) tv.scroll_mark_onscreen(buf.create_mark(nil, buf.end_iter, true)) true #繰り返し end end signal_connect("destroy") {Gtk.main_quit} show_all end Port = 29753 def server s = TCPServer.open(Port) puts "接続を待っています..." sock2 = s.accept sock1 = s.accept puts "接続しました" [sock1, sock2] end def client(host) [TCPSocket.open(host, Port), TCPSocket.open(host, Port)] end def get_names(sock1, sock2) print "名前を入力して下さい: " myname = STDIN.gets.chomp myname = "私" if myname.empty? sock2.puts myname hisname = sock1.gets.chomp hisname = "相手" if hisname == "私" puts "相手の名前は #{hisname} です。" [myname, hisname] end end def self.start MyWindow.new Gtk.main end end Oshaberi.start
Ruby/GTK2 については下も参考にしてみて下さい。
marginalia.hatenablog.com