質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Q&A

解決済

2回答

1397閲覧

Ruby socket whileから抜け出せない

kazuyakazuya

総合スコア193

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

0グッド

0クリップ

投稿2019/08/17 13:33

編集2019/08/18 12:12

Rubyのsocketを使ってクライアントからサーバーへコマンドを投げて
実行結果を表示するプログラムを作っています。

server

1#! ruby -Ku 2require "kconv" 3require 'socket' 4 5gate = TCPServer.open("55555") 6sock = gate.accept 7gate.close 8while cmd = sock.gets 9 puts(Kconv.tosjis(cmd)) 10 break if cmd == nil 11end 12sock.close 13

client

1#! ruby -Ku 2require "kconv" 3require 'socket' 4#ipconfigを実行し結果を投げる 5sock = TCPSocket.open("localhost","55555") 6sock.write(`ipconfig`) 7sock.close

問題なのはサーバー側のプログラムのここです。↓

ruby

1while cmd = sock.gets 2 puts(Kconv.tosjis(cmd)) 3 break if cmd == nil 4end

これはクライアント側文字列を受け取っています。
クライアント側から文字列をすべて受け取り切ったら

ruby

1break

を発動させ

ruby

1while

の処理を終わらせたいのですがどうすればよいのでしょうか?
ここでは

ruby

1break if cmd == nil

このように書いていますが、うまく作動してくれません。

すべて受け取り切ったら終了させたいのですが
その方法が全く思いつきません。
なにか良い方法はないでしょうか?
分からないので参考になるリンクまたは説明をお願いします。

追記

server

1#! ruby -Ku 2require "kconv" 3require 'socket' 4 5gate = TCPServer.open("55555") 6sock = gate.accept 7gate.close 8while cmd = sock.gets 9 puts(Kconv.tosjis(cmd))#ここはipconfigを表示する処理。 10end 11 12 13 14 15#コマンドを相手へ投げる。 16while msg = STDIN.gets 17 sock.write(msg) 18 while cmd = sock.gets#注意! ここはしっかり動作するかまだ立証していない 19 puts cmd #クライアントへ投げた文字列(実行したいコマンド)の結果をサーバー側で表示するための処理です。 20 end #注意! ここはしっかり動作するかまだ立証していない 21end 22sock.close 23

client

1#! ruby -Ku 2require "kconv" 3require 'socket' 4#ipconfigを実行し結果を投げる 5sock = TCPSocket.open("localhost","55555") 6sock.write(`ipconfig`) 7 8 9 10#受け取ったコマンドを実行する。 11while cmd = sock.gets 12 sock.write(`#{cmd}`)#注意! ここはしっかり動作するかまだ立証していない 受け取ったコマンド結果をサーバー側へ返す処理。 13end 14sock.close 15

大変わかりずらいですが
今回やっていること

1 クラアントがサーバーへipconfigの結果を投げる
2 サーバー側が受けと取り、結果を表示させたら
今回はサーバー側からクライアントへコマンドを実行するための文字列を投げる。

起こっていること
実行すると
#クライアントを実行

client

1C:\Users\matsu\Desktop\ruby_lesson>ruby client.rb 2

#サーバーを実行。

server

1・・・ 2・・・上記省略 3Wireless LAN adapter Wi-Fi: 4 5 接続固有の DNS サフィックス . . . . .: tcn-catv.ne.jp 6 リンクローカル IPv6 アドレス. . . . .: fe80::3908:b55c:8d55:59f2%18 7 IPv4 アドレス . . . . . . . . . . . .: 192.168.11.9 8 サブネット マスク . . . . . . . . . .: 255.255.255.0 9 デフォルト ゲートウェイ . . . . . . .: 192.168.11.1 10 11イーサネット アダプター Bluetooth ネットワーク接続: 12 13 メディアの状態. . . . . . . . . . . .: メディアは接続されていません 14 接続固有の DNS サフィックス . . . . .: 15#!ipconfigを表示したら本来ここから文字を打てる(クライアントへ投げるコマンド)はずだが 16打っても反応がない。!

要約すると
ipconfigを実行したクライアントがサーバーへ投げるところまで
はうまく作動している。
ただ、ipconfigの結果を表示し終えたところで文字の入力を受け付けていると思いきや
打っても反応がない。
今回の質問内容の場所に問題があるのかと思ったのですが
otnさんの指摘の通り
今回のwhileに問題はありませんでした。

どこに原因があるのでしょうか?・・・

さらに追記
whileに問題ないと書きましたが
breakしたところ次に処理が移ったので
やはりwhileに問題があるのかと思われます。

server

1#! ruby -Ku 2require "kconv" 3require 'socket' 4require 'time' 5 6gate = TCPServer.open("55555") 7sock = gate.accept 8gate.close 9 10while cmd = sock.gets 11 until(cmd = sock.gets) == "\004" 12 puts(Kconv.tosjis(cmd)) 13end 14 15while msg = STDIN.gets 16 sock.write(msg) 17 while cmd = sock.gets 18 puts(Kconv.tosjis(cmd)) 19 end 20end 21sock.close 22

client

1#! ruby -Ku 2require "kconv" 3require 'socket' 4#ipconfigを実行し結果を投げる 5sock = TCPSocket.open("localhost","55555") 6 7sock.write(`ipconfig`) 8sock.puts("\004") 9#受け取ったコマンドを実行する。 10while cmd = sock.gets 11 sock.write(`#{cmd}`) 12 13end 14sock.close

server

1 2Wireless LAN adapter Wi-Fi: 3 4 接続固有の DNS サフィックス . . . . .: tcn-catv.ne.jp 5 リンクローカル IPv6 アドレス. . . . .: fe80::3908:b55c:8d55:59f2%18 6 IPv4 アドレス . . . . . . . . . . . .: 192.168.11.9 7 サブネット マスク . . . . . . . . . .: 255.255.255.0 8 デフォルト ゲートウェイ . . . . . . .: 192.168.11.1 9 10イーサネット アダプター Bluetooth ネットワーク接続: 11 12 メディアの状態. . . . . . . . . . . .: メディアは接続されていません 13 接続固有の DNS サフィックス . . . . .: 14EOF 15

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

マニュアルを確認したうえでの回答でないので勘違いがあるかも、ですが
ポイントは

  1. sock.gets が nil を受け取るのはいつか
  2. sock.write(ipconfig) はnilを送るのか?

gets はファイルの終了(EOF) を受けると nil を返しますが、2)がEOFを送るのかどうか。もしかしたら送っていないのでは? closeで送るのでは? というのが第一感です。
最初のwhileの出口でdbg出力するとか、2つめのwhileのSTDIN.getsごとにpromptするとかしてみて確認してはどうでしょう。

もしそうだったら、sock.writeのあと意識的に終了の連絡を入れないとだめということになりますね。

投稿2019/08/18 02:59

winterboum

総合スコア23284

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kazuyakazuya

2019/08/18 05:33 編集

ありがとうございます。 クライアント側で Ctrl + Cで終了させたところ サーバーが次の処理に移行しました。 >Ctrl + C以外で終了させる連絡の方法はあるのでしょうか・・・
kazuyakazuya

2019/08/18 05:47

sock.closeでいけました!ありがとうございます。
winterboum

2019/08/18 06:38

write毎にopen close もなんですね。 EOF (^D) を送るのを試してみてください
kazuyakazuya

2019/08/18 06:41

やっぱだめでした・・・。 https://teratail.com/questions/206761 こちらのほうで再質問しています。 EOF (^D)を送るというのは sock.write(`ipconfig`) sock.write("EOF (^D)") ということでしょうか?
winterboum

2019/08/18 06:46

write("\cd") とか write("\004") とか
kazuyakazuya

2019/08/18 06:51

だめでした・・・。 本当にsock.write(`ipconfig`) の時点で処理が止まっているようです。
winterboum

2019/08/18 06:54

その処理のあとに close してうまく行ったように書いてありましたが、 どうなった のでうまく行ったと思ったが 実はこうだったから だめだ というのを教えて下さい
kazuyakazuya

2019/08/18 06:58

うまくいったようにみえたのですが あの時点で closeを呼び出してしまうと プロセス?そのものを終了させることになってしまいます。
winterboum

2019/08/18 08:19 編集

ああそうか、サーバからのを受信出来ないですね。 ※※ 訂正 gets で受けてるから、writeではだめだ client から ``` sock.write(`ipconfig`) sock.puts("\004"") して サーバ側で untile (cmd = sock.gets) == "\004" puts(Kconv.tosjis(cmd))#ここはipconfigを表示する処理。 end ``` では?
kazuyakazuya

2019/08/18 10:45

untile (cmd = sock.gets) == "\004"を付け足すと socket.rb:12:in `<main>': undefined method `untile' for main:Object (NoMethodError) というエラーになります。 あとこれは sock.puts("\004"") ダブルクォーテーションを2つつけるのですか?
winterboum

2019/08/18 11:44

あ、" はひとつです それから untile 綴間違えました until で、最後の e なしです
kazuyakazuya

2019/08/18 11:55 編集

server側を実行した時点でエラーになってしまいます。 socket.rb:21: syntax error, unexpected end-of-input, expecting keyword_end (ファイル名socket.rb サーバー) 一応コードを追記しました。 endを付けた場合にもエラーになります。
winterboum

2019/08/18 11:56

while cmd = sock.gets until(cmd = sock.gets) == "\004" puts(Kconv.tosjis(cmd)) end でなく until(cmd = sock.gets) == "\004" puts(Kconv.tosjis(cmd)) end です
kazuyakazuya

2019/08/18 12:00

ありがとうございます。 実行した結果 whileと同じ結果が返ってきます。 あと、今気づいたのですが 半角では打てなくなるのですが 全角では(enter押したら消えるけど)打てました。
winterboum

2019/08/18 12:08

"\004" でなく、目に判るように ”EOF" にしてみましょうか。 client serbver ともに。ipconfigの出力のあとに EOF って出るかどうか 全角でうつとかな漢字変換が間に入るので、確定するまではそういう動きになります。
kazuyakazuya

2019/08/18 12:13

server側の実行結果にEOFが現れました。 追記します。 ただ、やはり打てないです。
winterboum

2019/08/18 12:33

あ、改行があるな。 until(cmd = sock.gets) == "EOF\r\n" puts(Kconv.tosjis(cmd)) end と until(cmd = sock.gets) == "EOF\n" puts(Kconv.tosjis(cmd)) end を試して下さい
kazuyakazuya

2019/08/18 12:42

1回目のは変化がありませんでしたが 2回目を実行したら今度こそいけました! 詳しく対応していただきありがとうございます。
guest

0

break if cmd == nil

cmdnilならwhileの条件が偽なので、そこで終了です。

現状のコードでどういう現象になりますか?

投稿2019/08/17 14:02

otn

総合スコア84423

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kazuyakazuya

2019/08/17 14:10

申し訳ございません。 (今回の質問はわかりやすいように一部だけを取り上げていました。 原因はwhileかと思ったのですが 今回記載したwhileに関しては問題がありませんでした。) 追記します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問