- PR -

JavaとC#.netでのSocket通信

1
投稿者投稿内容
masakita
会議室デビュー日: 2005/02/13
投稿数: 3
投稿日時: 2005-02-13 04:33
はじめまして。
サーバーソケットをJava、
クライアントソケットをC#.net
でSocket通信をしたいと思っているのですが、
サーバーソケットがクライアントソケット
からのメッセージを受け取り、そのストリームからデータ
の最終行を取り出す時、エラーも発生せず、その箇所で
止まったままの状態になってしまいます。

以下がサーバーソケット(Java)です
-------------------------------------------------------
try {
  // サーバーソケットの生成
  ServerSocket mServerSocket = new ServerSocket(10000);
  try {
    // クライアントからの接続を待つ
    Socket socket = mServerSocket.accept();
    System.out.println(socket.getInetAddress() + "から接続を受付ました");
    // 入力ストリームを取得
    InputStreamReader isr = new InputStreamReader(socket.getInputStream());
    BufferedReader br = new BufferedReader(isr);
    // ●クライアントの入力ストリームに読み取るデータがある間ループ
    while(true)
    {
      if(br.ready() == true) {
         String inputLine;
         // ★最終行データを取り出す時、止まってしまう★
         inputLine = br.readLine();
         System.out.print(inputLine);
         if(inputLine == null) {
           break;
         }
      }
    }
  } catch (Exception e) {
    e.printStackTrace();
  }
}
-------------------------------------------------------

以下がクライアントソケット(C#)です
-------------------------------------------------------
//ホスト名からIPアドレスを取得
IPAddress hostadd = Dns.Resolve("serverhost").AddressList[0];
//IPEndPointを取得
IPEndPoint ephost = new IPEndPoint(hostadd, 10000);
//Socketの作成
Socket mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//接続
mSocket.Connect(ephost);
//接続の確認
if (mSocket.Connected == false) {
  Console.WriteLine("接続できませんでした。");
  return;
}

try
{
  // エンコードをデフォルトで取得
  Encoding encode = Encoding.Default;
  // 送信する文字列をバイト配列に変換
  // この際に、エンコードも同時に行う。
  byte [] bytData = encode.GetBytes("Line1\\r\\nLine2".ToCharArray());
  //メッセージを送信
  mSocket.Send(bytData, bytData.Length, SocketFlags.None);
}
catch( Exception ex) {
  System.Diagnostics.Debug.Write( ex.Message);
}
-------------------------------------------------------

なにかお気付きの点がありましたら
よろしくお願い致します。
パテ太
ベテラン
会議室デビュー日: 2004/08/16
投稿数: 64
お住まい・勤務地: 千葉・東京
投稿日時: 2005-02-13 10:38
引用:

masakitaさんの書き込み (2005-02-13 04:33) より:

    while(true)
    {
      if(br.ready() == true) {
         String inputLine;
         // ★最終行データを取り出す時、止まってしまう★
         inputLine = br.readLine();
         System.out.print(inputLine);
         if(inputLine == null) {
           break;
         }
      }




パテ太と申します。
違ってたら申し訳ありませんが
Java のソケットは Blocking/IO なので
inputLine == null の時は
そもそも br.ready = false のような気がします。
(while の終了条件が絶対に成立しないような気がします。)

また、最終行が取得できないのは
System.out.print(inputLine);
だからではないでしょうか?
このプログラムの場合は
System.out.println(inputLine);
でよいような気がします。
nak2k
ベテラン
会議室デビュー日: 2003/07/17
投稿数: 86
投稿日時: 2005-02-13 10:57
クライアントのほうで、データ送信後にソケットをCloseしてないからでは?

あと、サンプルとして挙げられたコードでしょうから的外れな指摘かもしれませんが
コード:
if(br.ready() == true) 


readLineメソッド内でどのみちデータが来るまで待機するはずですので、この判定は不要かと思います。
readLineメソッド内で待機させたほうがCPU使用率もあがらないでしょうしね。
masakita
会議室デビュー日: 2005/02/13
投稿数: 3
投稿日時: 2005-02-13 18:03
パテ太さん、k-nakさん、返信本当にありがとうございます。
メインの問題以外でも指摘いただき、とても参考になりました。

メインの問題もご指摘いただいたようにクライアント側
でCloseしてあげると最終行のデータを取得できるように
なりました。

最初に書くべき事だったと思うのですが、リアルタイムチャット
のようにサーバーとクライアントでリアルタイムな通信をしたい
と思っています。例として、あるクライアントからサーバーへ
メッセージを送信し、メッセージを受け取ったサーバーは接続さ
れている全クライアントへそのメッセージを送信するというよう
な内容です。このような場合、クライアントはメッセージを送信
する度にCloseを行わなければならず、その後にまたサーバーへ
接続要求し、サーバーとの接続を再度確立しなくてはならなくな
ると思います。

そこでこのような用件の場合、サーバーと接続状態を常に保てる
方法があるのでしょうか?
それともメッセージの送信の度、Closeを行い、再度サーバーとの
接続を確立するような方法の方がよろしいのでしょうか?
なお条件としてサーバーはJavaで、クライアントは.netです。

何かご存知であれば、ご教授いただけないでしょうか。
よろしくお願い致します。
nak2k
ベテラン
会議室デビュー日: 2003/07/17
投稿数: 86
投稿日時: 2005-02-13 21:25
リアルタイムチャットであれば、接続したままのほうがいいですね。

色々な設計が考えられるかと思いますが、サーバー側の設計としてはacceptする度にデータ受信用スレッドを作成、それらとは別に全クライアントにデータ送信を行うスレッドを1つ作成しておけばいいかと思います。

データ受信スレッドでは一行ずつ受信したデータを送信用のデータリストに追加。
データ送信スレッドではデータリストの先頭を見て、送信すべきデータがあったら、全クライアントに対してデータ送信を行うようにします。
送信先の管理はaccept時に、接続クライアントリストとしてリストに追加して管理すればいいでしょう。

データ送信スレッドは送信すべきデータがない場合は、 Object.wait メソッドで待機させたほうがよさそうですね。待機解除は、データ受信スレッドが送信データをリストに追加したときに、 Object.notify メソッドで行えそうです。
(ここらへん、Javaでのマルチスレッドプログラミング経験があまりないので、あまり自信ないです)

チャットとなるとクライアント側の受信もあるかと思いますが、そちらは Socket.BeginReceive メソッドのような非同期系メソッドを使ったほうがスレッド作らなくていい分、楽でしょうね。
送信処理は、サーバの処理が改行を受けるたびに他のクライアントへの送信を行うことになることさえ気をつければ問題ないかと思います。
Socket.Close 自体は通信を完全に終了するときに行うことになります。
パテ太
ベテラン
会議室デビュー日: 2004/08/16
投稿数: 64
お住まい・勤務地: 千葉・東京
投稿日時: 2005-02-13 22:14
パテ太です。
http://java.sun.com/docs/books/tutorial/networking/index.html
あたりが参考になるかと。
masakita
会議室デビュー日: 2005/02/13
投稿数: 3
投稿日時: 2005-02-14 09:35
返信ありがとうございました。

パテ太さんのリンクを参考にさせていただきながらサンプルを
作成し、実行してみた結果、
サーバーソケット側で受信メッセージを読み込む際、readLineではなく
readで1文字ずつデータを読み込んでいくと、最後の文字をread
した次のreadで止まってしまうようです。最後の文字を
read(止まる一歩手前の状態)した段階でbr.ready()がtrueからfalseへ
変化するのでこの状態変化を監視し、止まる直前で読み込みルーチン
をbreakし、接続されている全クライアントへメッセージを送信する
処理へ移行させられます。これならソケットをcloseしなくてもす
みそうです。
あとk-nakさんのご指摘のようにマルチスレッドでデータの送受信
をしてあげるようにしないといけないようですね。

以上を意識してやってみようと思います。
1

スキルアップ/キャリアアップ(JOB@IT)