「なでしこv1」開発掲示板

なでしこv1のバグや要望を書き込む掲示板
[一覧へ] > (@645) [低] [未処理]
@645■ (#2036) nakonetのUDP受信がエラーとなる - うぇいく (2012-08-28 16:21) /低 未処理
【症状】nakonetのUDPコンポーネントを利用して受信した場合、アプリケーションエラーとなってしまう。
【再現方法】以下のソースで確認(ただし、動作するかどうかはネットワーク環境に依存します)
-----
!変数宣言は必要
!初期化は必要
!「nakonet.nako」を取り込む。
CRとは文字列。
LFとは文字列。
CRLFとは文字列。
パケット1とは文字列。
接続状態とは整数

CR=「{\13}」
LF=「{\10}」
CRLF=「{CR}{LF}」

//※パケット1の中身は1行です。改行されてしまっていたら、つなげてください。
パケット1=「M-SEARCH * HTTP/1.1{CRLF}MX: 3{CRLF}HOST: 239.255.255.250:1900{CRLF}MAN: "ssdp:discover"{CRLF}ST: upnp:rootdevice{CRLF}{CRLF}」
//upnp:rootdevice
//ssdp:all
「起動中」と表示
接続状態は0

サーチとはUDP。
サーチのホストは「239.255.255.250」。
サーチのポートは1900。
サーチの受信した時は~
  「受信!」を表示
  サーチ→受信データを表示
サーチの接続した時は~
  「接続!」を表示
  接続状態は1
サーチのエラー時は~
  「えらー:{サーチ→エラーメッセージ}」を表示

サーチの接続

1秒待つ

接続状態が0と等しいの間
 1秒待つ
 「時間経過・・・」と表示

パケット1を表示
パケット1をサーチの送信
「送信・・・?」を表示

10回
 1秒待つ
 「時間経過・・・」と表示

「時間切れ」と表示
サーチを切断
「UDP切断」と表示

-----
【要望】エラーとならず、処理を継続したい。
【バージョン】ソースリポジトリ上のrev273
【その他】
 おそらくは、内部実装の変更の際に、変更漏れで中途半端な実装になっているようです。

 以下の2ファイル、3か所の修正が必要。

TNakoUdpのメンバのInstanceVarを削除。どこからも設定がされてない。
------- KTCPW.pas
    InstanceName: string;
    udpid: Integer;
    procedure setEvent;
-------
TNakoUdp.RecvDataにてInstanceVarを使う方法からInstanceNameの方法に変更。設定されないメンバ変数を参照してエラーになっている。
------- KTCPW.pas
  Move(pData^, s[1], len);
  s := InstanceName + '→受信データ=『' + s + '』;';
  nako_evalEx(PANsiChar(s), p);
  nako_var_free(p);
  //
  DoEvent('受信した時');
-------
TKUdpSocket.WndProc内のRecvPakcetの受信バイト数の変数はlenじゃなくてcnt。lenはaddr構造体の長さ。
------- UdpUnit.pas
      if Assigned(FOnRecieve) then
      begin
        FOnRecieve(Self, @RecvBuf[1], cnt);
      end;
-------



(#2039) 自側の設定の追加 - うぇいく (2012-08-27 21:58) /低 未処理
結局、こんな感じにuPnPを試しました。uPNPの1900はXP以降だとOSのサービスでも起動されるものがあるため、自側のポートが同じだと都合が悪いようです。
(別途、OSのサービスを停止すれば、送信側が1900でも動きます)
------dll_net_function.pas
      //---
      try
        p.PortNo := StrToIntDef(getToken_s(s, ':'), 80);
      except on e: Exception do
        raise Exception.Create('ポート番号が解決できません。');
      end;
      if s <> '' then
      begin
        try
          p.OwnHost := getToken_s(s, ':');
        except on e: Exception do
          raise Exception.Create('自ホスト名が解決できません。');
        end;
        try
          p.OwnPortNo := StrToIntDef(s, p.PortNo);
        except on e: Exception do
          p.OwnPortNo := p.PortNo;
        end;
      end else begin
        p.OwnHost := '';
        p.OwnPortNo := p.PortNo;
      end;
------
------UdpUnit.pas
    // 外部との対話用の接続管理
    FHost           : string;         // 接続先
    FPortNo         : Integer;
    FOwnHost        : string;         // 自側Host
    FOwnPortNo      : Integer;
    // イベント用
------
------UdpUnit.pas
    property Host: string read FHost write FHost;
    property PortNo: Integer read FPortNo write FPortNo;
    property OwnHost: string read FOwnHost write FOwnHost;
    property OwnPortNo: Integer read FOwnPortNo write FOwnPortNo;
  end;
------
------UdpUnit.pas
  // ポートの設定
  FSockAddr.sin_port         := htons(FOwnPortNo);
  FSockAddr.sin_family       := AF_INET;
  if FOwnHost = '' then
  begin
    FSockAddr.sin_addr.S_addr  := INADDR_ANY;
  end else begin
    FsockAddr.sin_addr.S_addr  := inet_addr(PAnsiChar(FOwnHost));
  end;
------
------nakonet.nako
 ・ポート{=60001}
 ・ホスト{=『225.0.0.0』}
 ・自ポート{=『』}  # 接続の時点で、1以上:その値 空:ポート同じ 0:自動
 ・自ホスト{=『』}  # 接続の時点で、空:ADDR_ANY IP:ネットワークIFのIP
------
------nakonet.nako
 ・接続~
   UDP_COMMAND(UDPID,"connect","{ホスト}:{ポート}:{自ホスト}:{自ポート}")
------

(#2040) 蛇足 - うぇいく (2012-08-28 22:09) /低 未処理
蛇足。手元のものは、以下のように書き換えました(受信イベントの受信データ設定、エラーイベントのエラーメッセージ設定、サーバソケットの相手IP設定の各所)
------KTCPW.pas
  p := nako_getGroupMember(PAnsiChar(InstanceName),PAnsiChar('受信データ'));
  if p <> nil then nako_bin2var(PAnsiChar(s),len,p);
  //s := InstanceName + '→受信データ=『' + s + '』;';
  //nako_evalEx(PANsiChar(s), p);
  //nako_var_free(p);
------
  ip := handle2ip(Target.Handle);
  p := nako_getGroupMember(PAnsiChar(InstanceName),PAnsiChar('相手IP'));
  if p <> nil then nako_str2var(PAnsiChar(ip),p);
  //s := InstanceName + '→相手IP=『' + ip + '』;';
  //nako_evalEx(PAnsiChar(s), p);
  //nako_var_free(p);
------
  p := nako_getGroupMember(PAnsiChar(InstanceName),PAnsiChar('エラーメッセージ'));
  if p <> nil then nako_str2var(PAnsiChar(E.Message),p);
  //s := InstanceName + '→エラーメッセージ=『' + E.Message + '』;';
  //nako_evalEx(PAnsiChar(s), p);
  //nako_var_free(p);
------

(#2036)へ返信する:

👆お手数ですが、いたずら防止のために、「真夏」の読み方を記入してください。

編集時に使うキーを入力(省略可能)

画像ファイル(最大300KB)を添付可能