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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

2回答

13281閲覧

TCP/IP受信にて、2電文つながったデータを受信したら、2電文受信できない。

nobysanz

総合スコア42

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

1グッド

1クリップ

投稿2015/12/04 04:03

編集2015/12/04 04:27

お世話になります。
C#にて、TCP/IP通信処理を行っております。
以下のような処理にて、一回の受信に、2つ電文がくっついて受信した場合、1電文づつ取得できずに、アプリケーションエラーとなります。

Socket.Receive を利用して、指定バイト数の受信は、保障されていると考えておりますが、
実は、指定バイト数以下でも受信することがありますでしょうか?
ご教授お願いいたします。

以下ソースです。

C#

1protected bool DataRecv(Socket client, out byte[] data) 2{ 3 int length = 0; 4 data = null; 5 6 if (client != null && client.Connected) 7 { 8 // ヘッダ部受信 9 int recvLength = client.Receive(_recvData, Telegrams.TelegramHeader.TELEGRAM_HEADER_SIZE, 0); 10 11 if (recvLength == 0) 12 { 13 // 0バイト受信(切断) 14 return false; 15 } 16 17 // データ部受信準備 18 // 受信電文からデータ部の長さを取得する 19 int dataLength = (int)(((_recvData[15] << Telegrams.TelegramHeader.TELEGRAM_OCTET) & 0xff00) | _recvData[14]); 20 length = Telegrams.TelegramHeader.TELEGRAM_HEADER_SIZE + dataLength; 21 22 // 1電文の格納領域を確保 23 data = new byte[length]; 24 25 // ヘッダ部を作業領域にコピー 26 Array.Copy(_recvData, data, Telegrams.TelegramHeader.TELEGRAM_HEADER_SIZE); 27 28 // データ部受信 29 recvLength = client.Receive(_recvData, dataLength, 0); 30 31 32 return true; 33 } 34 }
naoyan👍を押しています

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

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

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

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

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

ikuwow

2015/12/04 04:10

コードが見づらくなっていますので、Markdown記法でシンタックスハイライトしていただけると助かります。
guest

回答2

0

ベストアンサー

こういう低いレベルの関数は、受信したデータがあれば、それだけを返します。
データ長に100を指定していても、10バイト受信したら、第一引数のエリアに10バイトコピーして、その時点でリターンして10を返値とします。
150バイト受信したら、100バイトをコピーして、50バイトをOSの受信バッファに残し、100を返値としてリターンします。直後(次の受信前)に再度呼び出すと、残っている50バイトをコピーして50を返値としてリターンします。
つまり、引数で指定数長さは取得できるデータ長の最大値です。
欲しいだけのデータ長が出そろうまでループするように、自分で書く必要があります。

上記の説明で「受信したら」というデータは、OSの受信バッファに未取得のデータが残っていればその残っているデータのことで、OSの受信バッファが空でブロッキングモードの時は次に受信するまで待ってそのデータのことです。

なお、送信側で長いデータを1回で送信しても、受信側では短く何度にも分けて受信することがあります。

投稿2015/12/04 14:06

otn

総合スコア84505

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

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

nobysanz

2015/12/07 12:29

コメントありがとうございます。Receiveで、指定する長さは、あくまで最大受信データ長なのですね。理解できました!
guest

0

available が非0である限り再読み込みしてくれ、って書いてありますよ。
memorystream か何かを引数に取るオーバーロードがあるんじゃないかと、検索したら無いですね。
じゃ基本に戻って、読み込みバッファサイズ1で available >0の間、
socket.recieve して、受信DATAを memorystreamにかきこみ、
完了したら、byte 配列にコンバートして返す処理、
バイト配列をヘッダとデータ部のセットに切り分ける処理、これも結果は配列になる、
この配列を逐次処理する、パケット解析する処理、

ですね。どこに書いてあるか?msdn 見てください。
socket.recieve のオーバーロード一覧、 memorystream、などでづ。

投稿2015/12/04 04:50

ipadcaron

総合スコア1693

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

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

nobysanz

2015/12/04 04:59

コメントありがとうございます。 msdn 見てみます。
nobysanz

2015/12/04 13:41

シリアル通信のように、1バイトづつ読み込んで、バッファに読み込ん処理することですね。Receveのパラメータに、レングスがあるため、必ず、指定レングスの受信バイト数を満たしたときに、Receve完了となると考えていました。指定レングスに満たさない時にも、Receve完了となるのでしょうか? 
nobysanz

2015/12/12 08:35

自己レスです。 テストプログラムを作成し、本件確認しました。socket recive メソッドの指定レングス以下でも受信されていました。受信バイト数は、あくまで、受信データを格納するエリアの最大バイト数を指定していることなのですね。 受信バイト数をチェックし目的のデータ数を受信するようにします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問