No.7
- 回答日時:
速度を計るのですか。
かなり重要なことを忘れていましたね。。。
そのように、しっかりした目的があるなら、もう少しまじめに
検討する必要があります。
とりあえず、前回のことは忘れてください。
●まず、速度を計るということは、データを無限ループ的に回すのではなく、
1周させることが目的となるわけです。
何度も計りたいのなら、1周という単位の仕事を複数回繰り返すことになります。
そうすると、考え方が変わってきますね。
実現するには、1周したかどうかの判定が必要になります。
方法はいろいろあると思いますが、送るデータにゴールのマシンのIPアドレスを
入れておくのが簡単でしょう。
ということは、送るデータに約束事(プロトコル)が必要になってくるわけで、
まずはこれをしっかり決めておかなければなりません。
とりあえず、次のようなものでどうでしょうか。
・改行までが1レコード
・空行があれば、データ終了
・レコード内のデータは次のようにエスケープする。
・&は&
・0x0Dは&CR;
・0X0Aは&LF;
・1行目はコマンド
コマンドは、'transport'か'start'
(コマンドがtransportの場合)
・2行目は、ゴールとなるIPアドレス
・3行目は、スタートした時刻
・4行目以降は任意。
・転送する場合は、データの全てを転送する
(コマンドがstartの場合)
・2行目以降は任意。
転送するのは、このまとまりの単位になります。
*コマンドのstartは、転送開始を意味していて、A-B-C-D-B-C-D...
の流れの、A-B間のプロトコルを想定しています。
●次に、受信・送信ですが、送信が終わるたびにセッションを切った方が流れがすっきり
すると思います。(これは主観によりますけど)
●以上をふまえて、セッションの基本的な流れを考えると、
Socket socket = serverSocker.accept();
if(transportコマンド判定){
//データの受信
...
...
//ゴール判定
if(ゴールの場合){
//ゴールの処理
...
...
}else{
//転送処理
...
...
}
}else
if(startコマンド判定){
//転送処理
...
...
}
socket.close();
となります。
●このままでは、1度受信をすると、プログラムが終了してしまうため、
ループで囲みます。
for( ; ;){
Socket socket = serverSocker.accept();
...
...
socket.close();
}
●このままではセッションが終了するまで、他からの接続ができないので、
普通のサーバーのプログラムは、受信後の処理はスレッドにして、すぐにループに
復帰するようにしますが、今回の場合はそこまでしなくてもいい気がします。
for( ; ;){
Socket socket = serverSocker.accept();
MySessionThread session = new MySessionThread(socket);
session.start();
}
●順を追って説明したつもりですが、わからない箇所があれば質問してください。
この回答への補足
3つ質問があります。
>・レコード内のデータは次のようにエスケープする。
・&は&
・0x0Dは&CR;
・0X0Aは&LF;>
この意味がよくわからないのですが、どの分野を勉強すればいいのですか?
>コマンドは、'transport'か'start'>
コマンドとは、プログラムをコンパイルした後に、コマンド入力するするということなんでしょうか。私は、以下の様に解釈したのですが、、最初にメッセージを受け取る場合は'transport',送る場合は、'start'の選択をします。
入力ストリームを使って、ユーザがキーボードで打ち込んで選択しています。
System.out.println("Please transport or start input!!");//送信側か受信側か選択する
InputStreamReader input = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(input);
String s;
while((s = br.readLine()) != null) {
}...........
また、transportを選択して、ゴールならば、//ゴールの処理は、一周ごとに書き換えられ、カウントとタイムを計る。そうでなければ、転送処理をするためソケットを作って、出力ストリームを用意して、次のサーバに転送すると解釈したのですが以下の※1には、カウントとタイムを計る他に転送する処理が必要ではないのでしょうか。(一周してゴールすると止まってしまうと思ったのですが、)
>if(transportコマンド判定){
//データの受信
...
...
//ゴール判定
if(ゴールの場合){
//ゴールの処理 ※1
...
...
}else{
//転送処理
...
...
}
}else>
この方法だとそれぞれのマシンに同じプログラムを入れることで、A-B-C-D-A-B-C-D...と一周する方がいいいみたいですね。
一通り書いてみましたが、IPアドレスとスタートした時間をメッセージと一緒に渡す方法などまだできてません。
理解できていない点もあり質問内容があいまいですが、ご回答の方よろしくお願いします.
No.6
- 回答日時:
もうひとつ、先にお断りしておきますが、私の方針でズバリのコードは書きませんので
ご了承下さい。
そのかわり、わかる範囲でなら、しつこく付き合います。
>イ.マシンAから、何かを受け取ったら、すぐに転送する。>
>
>イをやりたいと考えております。
わかりました。
確認しておきますが、そうすると、2バイト以上のデータを流す場合、
データが入り組んでしまいますが、よろしいのでしょうか?
やはり、ある程度のまとまりで送った方がいいと思いますけど。
例えば、改行までの1行ごとにおくるとか。
そうしないと、ごちゃごちゃになりますよ。
それと、プログラムの構造がおかしいようです。
基本的な構造は、
・次をループで回す
・前のサーバーからデータを読む
・次のサーバーへ転送
となります。
もう少し具体的には、
InputStream is = prevSocket.getInputStream();
OutputStream os = nextSocket.getOutputStream();
for( ; ; ){
int c = is.read();
os.write(c);
}
と、こんな感じです。
このままだと、先ほど説明したように、ごちゃごちゃになりますから、
1行分を読んでから、書き込みをする等の工夫がいるでしょう。
この流れからいくと、前のサーバーと次のサーバーの両方に対して、
接続をしておかなければなりません。
とすると、次のサーバーの情報は、プログラム起動直後に設定してしまうのが
いいと思います。
ただし、接続するのは受信をした後です。起動直後では、次のサーバーが起動していない
可能性があるからです。
main(){
//次のサーバーの情報(IPアドレス、ポート番号)を入力
(入力処理)
//受信待ち待機
Socket prevSocket = server.accept();
//次のサーバーへ接続
Socket nextSocket = .....
InputStream is = prevSocket.getInputStream();
OutputStream os = nextSocket.getOutputStream();
for( ; ; ){
int c = is.read();
os.write(c);
}
もう一度見直しをして下さい。
この回答への補足
>そのかわり、わかる範囲でなら、しつこく付き合います。>
ありがとうございます。感謝しております。
>1行分を読んでから、書き込みをする等の工夫がいるでしょう。>
について、while((s = dis.readLine()) != null) のように改行ごとに読み込むように書き換えました。
ひとついい忘れましたことがありました。最終的には、Aが「Hello」と言うメッセージを投げると、受け取った複数のサーバ同士でリング状にグルグル回し、速度を測るアプリケーションを作ることが目標です。よって
>//次のサーバーの情報(IPアドレス、ポート番号)を入力
(入力処理)>
を、ホスト名、ポート番号を指定してnextSocket = new Socket("sougou2-2",5555);//次のサーバーへ接続
と書き換えました。
私からの質問2つあるのですが
(1)readLine()で読み込んだのをwriteUTF()、writeChars()で書き込もうとすると、コンパイルで推奨されないAPIと警告が表示されます。どう書き換えればいいのかが分りません。
(2)速度を測るアプリケーションを作るには、入出力をDataInputStreamとBufferedInputStreamなどをどちらを記述すれば、最小限の効率の良い実装ができるのでしょうか?
以下、見直して書き換えました。よろしくお願いします。
import java.io.*;
import java.net.*;
import java.lang.*;
//メインクラス
class revp2p3 {
public static void main (String args[]) {
try {
System.out.println("サーバの用意始めます");
while(true){
ServerSocket ss = new ServerSocket(5555);
Socket prevSocket = ss.accept();//受信待ち待機
Socket nextSocket = new Socket("sougou2-2",5555);//次のサーバーへ接続
InputStream is = prevSocket.getInputStream();
DataInputStream dis = new DataInputStream(is);
OutputStream os = nextSocket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
String s;
while((s = dis.readLine()) != null) {
System.out.println("メッセージ" + s);
dos.writeUTF(s);
}
ss.close();
dis.close();
dos.close();
}
}
catch(IOException e){
System.out.println("IOException main "+e);
}
catch(Exception e){
System.out.println("Exception main "+e);
}
}
注: revp2p3.java は推奨されない API を使用またはオーバーライドしています。
注: 詳細については、-deprecation オプションを指定して再コンパイルしてください。
No.5
- 回答日時:
はじめから、そのように書いてもらえれば、無駄がなかったのですが。
。。質問する側は、教えてもらうという立場なのですから、
文章を面倒がってはいけませんね。
まあ、説教はこのくらいにして。。。
●補足要求
2度手間になりそうな予感があるので、まず仕様に関して確認しておきたいことがあります。
データの送るタイミングの問題です。
マシンBがマシンCに転送するのは、次のどちらのタイミングでしょうか?、
ア.マシンAから全てを受け取ってから、マシンCに転送する。
イ.マシンAから、何かを受け取ったら、すぐに転送する。
コードを見ると、「イ」のパターンでやりたいようにも見えますが、
実際は「ア」のパターンで動作しています。
*先にお断りしておきますが、私は土日曜日は返事ができません
この回答への補足
はい。次回からは気をつけますm(_ _)m
*先にお断りしておきますが、私は土日曜日は返事ができません>
分りました.
●補足要求返答
イ.マシンAから、何かを受け取ったら、すぐに転送する。>
イをやりたいと考えております。
No.4
- 回答日時:
>複数のパソコンにサーバプログラムを入れているので、
はあ?
また変なことを言ってますね。
私からの質問は、ちゃんと理解してますか?
動作させている環境を正確に説明してください。
初心者であることと、人の話を聞かないことは関係ありません。
この回答への補足
>複数のパソコンにサーバプログラムを入れているので、
すみません。何度も、、質問の意味を理解できていませんでした。
windows2000環境で3台のパソコンを起動させて、そこでjavaプログラムを動かしています。例えば、パソコンAはメッセージを投げる役割をするのみのプログラムがあり、パソコンBとCは、先ほど書いたrevp2p2javaプログラムを実装させています。
BとCを先にコンパイル実行してメッセージ待ち状態にします。A→B→C→B→C→B→C....とBとCの間で無限ループでグルグル回したいのです。
そこでBがAからメッセージを受け取ったんですけど、Cへ渡すことができない状態なのです。
最終的には、同様にAのプログラムを一台、B~H...のプログラムを複数増やしてB~H...にメッセージを渡して、リング状に回したいのです。
こんな感じでいいでしょうか?
No.3
- 回答日時:
ServerクラスとClientクラスが何をしているのかわからないため断言は出来ませんが、
1台のマシンで動かしているということなので、複数のサーバープログラムが
同一のソケットで動こうとしてませんか?
1つのマシンでは、1つのポートに対し、1つのサーバープログラムしか動かせませんよ。
確認してみてください。
それとは別に、mainメソッドでsocketをクローズしてますが、おかしくありませんか?
Serverクラスのコンストラクタに渡しているのだから、Serverクラスで使っているような
気がするのですが。
もし、そうなら、mainメソッドでクローズするのは問題があると思いますけど。。。
この回答への補足
サーバクラスでsocketを閉じるのですね。分かりました。ありがとうございます。複数のパソコンにサーバプログラムを入れているので、サーバークラスではメッセージを受け取る為、入力ストリームを取得しています。クライアントクラスでは、出力ストリームを取得し、相手の宛先を新しく指定して、受け取ったメッセージを渡したいのですけど、クライアントメソッドがスタートした後は、サーバクラスの待ち状態になるようにしたいのです。すみませんけど、アドバイスをお願いします。
//サーバクラス
class Server extends Thread{
Socket socket;
Client client;
public Server(Socket socket) {
this.socket = socket;
}
public void start() {
//debug
System.out.println("サーバ呼び出しました");
try{
//debug
System.out.println("サーバ稼動中");
BufferedReader in = new BufferedReader(//入力ストリーム
new InputStreamReader(
socket.getInputStream()));
String message = in.readLine();
System.out.println("読み込んだメッセージは" + message);
socket.close();
in.close();
}
catch(Exception e){
System.out.println("Exception "+e);
}
}
}
//クライアントクラス
class Client extends Thread {
String ip;
int port;
String message;
public Client(String ip, int port) {
this.message =message;
this.ip =ip;
this.port = port;
}
public void start(String message) {
try{
Socket socket = new Socket(ip,port);
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
out.writeChars(message);//出力ストリームと共に隣りへ送信する。
socket.close();
out.close();
}
catch(Exception e){
System.out.println("Exception "+ e);
}
}
}
No.2
- 回答日時:
答えがおかしいですよ。
マシンのことですか?
→はい、そうです。
(マシンのこと?)
プログラムのことでローカルで通信しています。
(やっぱり、プログラムのこと?)
どっちなのですか?
この回答への補足
プログラムのことです。すみません。
サーバ側のプログラムのmainは以下のとおりです。
よろしくお願いします。
class revp2p2 {
public static void main (String args[]) {
try {
System.out.println("サーバの用意始めます");
while(true){
//Debug
ServerSocket ss = new ServerSocket(5555);
System.out.println("受信を待ちうけます");
Socket socket = ss.accept();//クライアントから要求を受け取る
Server server = new Server (socket);
server.start();
System.out.println("サーバスレッド呼び出し完了");
System.out.println("IPとポートを指定する");
BufferedReader d = new BufferedReader(new InputStreamReader(System.in));
String ip = d.readLine();
int port = Integer.parseInt(d.readLine());
socket.close();
Client client = new Client(ip,port);
client.start();
System.out.println("クライアントスレッド呼び出し完了");
}
}
catch(IOException e){
System.out.println("IOException main "+e);
}
catch(Exception e){
System.out.println("Exception main "+e);
}
}
}
No.1
- 回答日時:
補足要求をします。
1.サーバーと言っているのは、マシンのことですか?
つまり、複数台のマシンにそれぞれサーバーのソフトが動いているのでしょうか?
2.エラーが出るタイミングをもう少し詳しく説明してください。
この回答への補足
1.はいそうです。サーバーとは、プログラムのことでローカルで通信しています。以下にサーバとして起動しているプログラムの内容を記述さしてもらいます。
main文の内容(whileで無限ループしてます)
ServerSocket ss = new ServerSocket(5555)
Socket socket = ss.accept();
Server server = new Server (socket);
server.start();
System.out.println("IPとポートを指定する");
BufferedReader d = new BufferedReader(new InputStreamReader(System.in));
String ip = d.readLine();
int port = Integer.parseInt(d.readLine());
socket.close();
Client client = new Client(ip,port);
client.start();//ここでエラーが出ます
main文では、socketを2度生成できないということでしょうか?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- その他(メールソフト・メールサービス) Thunderbirdのメール送信ができません 1 2022/10/28 16:54
- docomo(ドコモ) +メッセージの送受信。 au(uq mobile)のデータ回線でdocomoの電話番号の+メッセージ 2 2022/09/14 16:09
- サーバー メールサーバーについて詳しい方、メールサーバーの管理業務経験のある方、教えてください。 3 2022/11/12 18:24
- サーバー FTPサーバについて詳しい方(アクセス権のないディレクトリを非表示にする方法) 4 2022/08/22 22:33
- サーバー 接続・ログインはできているのにメールが送信できない 2 2022/06/27 15:03
- LINE LINEのスマホ機種変更時の移行失敗の復旧 1 2022/06/20 14:52
- PHP PHP でメールフォームを作成したい 1 2022/05/04 22:28
- サーバー 別サーバに構築したApache+Tomcatの連携について 2 2023/03/06 23:23
- Yahoo!メール Yahooアカウントにログインできなくなって困っています。 2 2023/05/16 02:28
- ノートパソコン ESETの初期インストールの仕方 1 2022/10/14 08:26
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
「タイプ初期化子が例外をスロ...
-
ファイルダイアログを開いた時...
-
【JAVA】与えられた金額を貨幣...
-
スタックオーバーフローとは?
-
文字列が数字のみで構成されて...
-
nullで、return出来るのはどん...
-
ADOによるレコードの追加/更新
-
VB.Net Object型 空かどうか
-
Javaで文字列をゼロ埋め(ゼロパ...
-
時間の取得
-
WebClient()以外でネットにアク...
-
WMIスクリプトを使用してMACア...
-
例外ってIf文の中に入れますか...
-
VBA 400エラー 1004エラー
-
文字列からダブルクオートの削除
-
C#の捕捉されない例外処理の対...
-
String型の日付(2005/11/25)の...
-
オーバーライドしたメソッドで...
-
VBA ユーザーフォーム ラベル...
-
0除算の例外処理ができない!!...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
「タイプ初期化子が例外をスロ...
-
【JAVA】与えられた金額を貨幣...
-
連続する「\\」をひとつの「\\...
-
文字列からダブルクオートの削除
-
VB.Net Object型 空かどうか
-
0除算の例外処理ができない!!...
-
VB.NETで16進数が正しいかどう...
-
数字か文字列かを判定する関数
-
例外ってIf文の中に入れますか...
-
C# マルチスレッドにおける例外...
-
スタックオーバーフローとは?
-
String型の日付(2005/11/25)の...
-
Timestamp型への変換について(J...
-
C# UriFormatExceptionの回避
-
VBA Evaluate関数 型が一致しま...
-
ADOによるレコードの追加/更新
-
時間の取得
-
WebClient()以外でネットにアク...
-
C#の捕捉されない例外処理の対...
-
タトゥーや墨を入れる人の共通点
おすすめ情報