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

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

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

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

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Socket.IO

Socket.IOはNode.js上で動くライブラリであり、すべてのブラウザとモバイルデバイスでリアルタイムのアプリを作動させる事を目的としています。

Xamarin

Xamarin(ザマリン)は、iPhoneなどのiOSやAndroidで動作し、C# 言語を用いてアプリを開発できるクロスプラットフォーム開発環境です。Xamarin Studioと C# 言語を用いて、 iOS と Android の両方の開発を行うことができます。

Q&A

解決済

1回答

650閲覧

Android9のTCP通信で、急に受信(クライアント側)が止まってしまう

TAKE_SS

総合スコア40

C#

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

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Socket.IO

Socket.IOはNode.js上で動くライブラリであり、すべてのブラウザとモバイルデバイスでリアルタイムのアプリを作動させる事を目的としています。

Xamarin

Xamarin(ザマリン)は、iPhoneなどのiOSやAndroidで動作し、C# 言語を用いてアプリを開発できるクロスプラットフォーム開発環境です。Xamarin Studioと C# 言語を用いて、 iOS と Android の両方の開発を行うことができます。

0グッド

0クリップ

投稿2022/12/07 05:32

編集2022/12/09 07:59

発生している問題

TCP通信で、PC側をサーバーとし、Android端末(タブレット)をクライアントとして、サーバーからの1秒間隔での通信を受信する処理を行っています。
AndroidはVisualStudio2022上(xamarin)で開発しています

正常に受信している間はなんともないのですが、急にAndroidに受信が届かなくなる(受信出来ない)事象があり、困っています。10分程度で発生するときもありますが、長いと1時間半後に発生するなど,発生するまでの時間に統一性はみられません。
サーバー側は送信を続けており、特にエラーにはなっていません。

この状態を放置してずっと受信待ちにしていると、受信が再開する場合があるようです。

また、同じアプリをAndroid7の端末で動かすと特に問題は発生しません。
受信するクライアントをPC側に別アプリで動かしても特に問題はありません。

何か、解決方法又は調査方法など、教えて頂けると助かります

環境

PC側:Windows7
Android側:アプリはVisualStudio2022上(xamarin)で作成
Android7端末:HUAWEI MediaPad M3 Lite 10
Android9端末:Logtec LT-MS10/BCC2

試したこと・確認したこと

・受信が止まったとき、その前にアプリの受信側(ReceiveCallback)でエラーや
例外が起きていないか
⇒ 特に問題なし
・回線をいったんクローズして再オープンするとどうなるか
⇒ 正常に受信が開始される
・Android7端末とAndroid9端末で同じアプリを動かしてみると、Android9の方だけ受信が来なくなってしまう
・wifiの接続を2.4Gから5Gに変更しても、頻度が変わるが発生する
(たまたまの可能性があるが、2.4Gの方が頻度が高かった)

ソースコード

サーバー側(Windows7)

C

1bool CNetSv::Create(int nPort, HANDLE evtClose, CWnd *pPair/* = nullptr*/) 2{ 3 if (nPort == 0){ 4 return true; 5 } 6 m_nPort = nPort; 7 m_evtClose = evtClose; 8 m_pPair = pPair; 9 if (!CAsyncSocket::Create(nPort)){ 10 return false; 11 } 12 if (!Listen()){ 13 return false; 14 } 15 16 m_bConnect = true; 17 18 return true; 19} 20 21void CNetSv::OnAccept(int nErrorCode) 22{ 23 CNetCl *pCL; 24 sockaddr_in saAddr; 25 int nLen = sizeof(saAddr); 26 if (nErrorCode != 0){ 27 return; 28 } 29 30 // 空き番を探して登録 31 for (int i = 0; i < 50; i++){ 32 if (m_mapCL.find(i) == m_mapCL.end()){ 33 pCL = new CNetCl(i, m_evtClose, m_pPair); 34 Accept(*pCL, (SOCKADDR*)&saAddr, &nLen); 35 pCL->SetAddr(saAddr.sin_addr); 36 m_mapCL[i] = pCL; 37 break; 38 } 39 } 40 41 CAsyncSocket::OnAccept(nErrorCode); 42} 43void CNetSv::Send(LPCTSTR szData, size_t nSize) 44{ 45 std::map<int, CNetCl*>::iterator it = m_mapCL.begin(); 46 47 // 接続がない場合は終了 48 if (!m_bConnect)return; 49 50 // 送信先がない場合は終了 51 if (m_mapCL.size() <= 0) return; 52 53 // データにSTX,ETX,BCCを付ける 54 char *szSend; 55 char cBCC = 0; 56 57 szSend = new char[nSize + 4]; // STX,ETX,BCC,NULL分を付加 58 59 // STX付加 60 szSend[0] = STX; 61 // データをコピー(+BCC計算) 62 for (size_t i = 0; i < nSize; i++) { 63 szSend[i + 1] = szData[i]; 64 cBCC ^= szData[i]; 65 } 66 // ETX付加 67 szSend[nSize + 1] = ETX; 68 // BCC付加 69 szSend[nSize + 2] = cBCC ^ETX; 70 71 // 全接続にデータ送信 72 while (it != m_mapCL.end()) { 73 it->second->Send(szSend, nSize + 3); 74 ++it; 75 } 76 77 delete[] szSend; 78} 79

クライアント側:Android(xamarin)

C#

1private static Socket TcpClient = null 2 3// 同期ソケット用クラス 4class AsyncStateObject 5{ 6 public Socket socket; 7 public byte[] buffer; // 受信バッファ 8 public byte[] WkBuffer; // 処理用のバッファ 9 public int WkLen; // 処理途中のレングス 10 public AsyncStateObject(System.Net.Sockets.Socket soc) 11 { 12 this.socket = soc; 13 this.buffer = new byte[1024]; 14 this.WkBuffer = new byte[0]; 15 this.WkLen = 0; 16 } 17} 18 19<オープン> 20TcpClient = new Socket(SocketType.Stream, 0); 21TcpClient .ReceiveTimeout = 5000; 22TcpClient .SendTimeout = 5000; 23TcpClient .Connect(Address, Port);  // AddressはIPアドレス、Portは9900等 24 25<受信コールバック> 26private void ReceiveDataCallback(System.IAsyncResult ar) 27{ 28 //状態オブジェクトの取得 29 AsyncStateObject so = (AsyncStateObject)ar.AsyncState; 30 DateTime dNow = DateTime.Now; 31 Log.Debug("【ReceiveDataCallback】", "受信" + dNow.ToString("mm:ss.fff")); 32 33 //読み込んだ長さを取得 34 int len = 0; 35 try 36 { 37 len = so.socket.EndReceive(ar); 38 } 39 catch (Exception e) 40 { 41 //閉じた時 42 var strError = e.Message; 43 Log.Debug("【ReceiveDataCallback】", "接続が閉じました。:" + strError ); 44 if (so.socket != null) 45 { 46 so.socket.Close(); 47 TcpClient = null; 48 } 49 return; 50 } 51 52 //切断されたか調べる 53 if (len <= 0) 54 { 55 // エラー通知 56 Log.Debug("【ReceiveDataCallback】", "接続が切断されました。"); 57 if (so.socket != null) 58 { 59 so.socket.Close(); 60 TcpClient = null; 61 } 62 return; 63 } 64 65 try 66 { 67 //受信したデータを蓄積する 68 int DataSize = so.WkLen + len; // 処理レングス算出(前回の残り+今回受信) 69 Array.Resize(ref so.WkBuffer, DataSize + 1); // 処理用バッファをリサイズ(前回の残り+今回受信+1) 70 Array.Copy(so.buffer, 0, so.WkBuffer, so.WkLen, len); 71 byte[] rcvDataWk = new byte[DataSize]; 72 byte[] restData = new byte[DataSize]; // 未処理データが残った場合の待避用 73 int nRecv = 0; // 処理済みデータレングス 74 for (int i = 0; i < DataSize; i++) 75 { 76 if ((so.WkBuffer[i] == STX) && (m_eRecv != RCVTYPE.chek)) 77 { 78 m_cBcc = 0; // bcc初期化 79 Array.Clear(rcvDataWk, 0, rcvDataWk.Length); 80 m_nRecv = 0; 81 m_eRecv = RCVTYPE.recv; // 受信中 82 } 83 else if ((so.WkBuffer[i]) == ETX && (m_eRecv == RCVTYPE.recv)) 84 { 85 rcvDataWk[m_nRecv] = 0x0; 86 m_cBcc ^= so.WkBuffer[i]; 87 m_eRecv = RCVTYPE.chek; // BCC待ち 88 } 89 else if (m_eRecv == RCVTYPE.chek) // BCCチェック 90 { 91 if (so.WkBuffer[i] == m_cBcc) // BCC一致 92 { 93 DataProc(ref rcvDataWk, m_nRecv); 94 nRecv = nRecv + (m_nRecv + 3); // 未処理データレングス算出 95 } 96 m_eRecv = RCVTYPE.none; 97 } 98 else 99 { 100 rcvDataWk[m_nRecv++] = so.WkBuffer[i]; 101 m_cBcc ^= so.WkBuffer[i]; 102 if (m_nRecv > 4095) 103 { 104 m_nRecv = 0; 105 m_eRecv = RCVTYPE.none; 106 } 107 } 108 } 109 110 if (m_eRecv != RCVTYPE.none) // 受信処理未完(データ途中) 111 { 112 int nRestLen = DataSize - nRecv; // 未処理データレングス算出(受信データ-処理済みデータ) 113 if (nRecv > 0) // 処理済みがあるとき(受信が多かったとき) 114 { 115 Array.Copy(so.WkBuffer, nRecv, restData, 0, nRestLen); // 待避用バッファに残りをコピー 116 Array.Resize(ref so.WkBuffer, nRestLen + 1); // 処理用バッファをリサイズ(残りのみ) 117 Array.Clear(so.WkBuffer, 0, nRestLen + 1); 118 Array.Copy(restData, 0, so.WkBuffer, 0, nRestLen); // 待避したデータを戻す 119 } 120 so.WkLen = nRestLen; // 途中のレングス保存 121 m_eRecv = RCVTYPE.none; // 状態クリア(次回は先頭から解析) 122 } 123 else 124 { 125 so.WkLen = 0; 126 m_nRecv = 0; 127 } 128 } 129 catch (Exception ex) 130 { 131 var strError = ex.Message; 132 Log.Debug("【ReceiveDataCallback】", "Exception"+ex.Message); 133 m_eRecv = RCVTYPE.none; 134 so.WkLen = 0; 135 m_nRecv = 0; 136 } 137 138 //再び受信開始 139 so.socket.BeginReceive( 140 so.buffer, 141 0, 142 so.buffer.Length, 143 System.Net.Sockets.SocketFlags.None, 144 new System.AsyncCallback(ReceiveDataCallback), 145 so); 146 } 147

クライアント側2:Android(xamarin) この受信処理でもReceiveDataCallbackが来なくなっている

C#

1public class SockClient 2{ 3 4/// <summary> 5/// 同期オブジェクト(Socket同時使用防止用) 6/// </summary> 7private object syncSocket = new object(); 8 9private void ReceiveCallback(IAsyncResult ar) 10{ 11 Debug.Print("【ReceiveCallback】受信"); 12 int bytes; 13 // 自インスタンス取得 14 SockClient Me = (SockClient)ar.AsyncState; 15 // ソケット取得 16 Socket sock = Me.clSock; 17 // 既に閉じられている場合は終了 18 if ((sock == null) || (!sock.Connected)) 19 { 20 Debug.Print("【ReceiveCallback】Socketが閉じている"); 21 return; 22 } 23 24 try 25 { 26 // クライアントソケットから受信データを取得終了 27 lock (syncSocket) bytes = sock.EndReceive(ar); 28 } 29 catch(Exception ex) 30 { 31    Debug.Print("【ReceiveCallback】EndReceiveエラー:" + ex.Message); 32    bytes = 0; 33 } 34  if (bytes > 0) 35 { 36 // 受信処理 37 onReceiveAll(Me, bytes); 38 try 39 { 40 // 受信時のコードバック処理を再設定 41 lock (syncSocket) sock.BeginReceive(Me.Buffer, 0, BuffSize, 0, new AsyncCallback(ReceiveCallback), Me); 42 Debug.Print("【ReceiveCallback】onReceiveAll & BeginReceive "); 43 return; 44 } 45 catch { 46 string Msg = $"例外:{Me.IPEndPoint?.Address.ToString()}({Me.IPEndPoint?.Port})"; 47  Debug.Print(errMsg); 48 } 49 } 50 51 string errMsg = $"切断:{Me.IPEndPoint?.Address.ToString()}({Me.IPEndPoint?.Port})"; 52 Debug.Print(errMsg); 53 54 OnDisconnect?.Invoke(this, Me); 55 Me.clSock = null; 56 Me.IPEndPoint = null; 57 58 sock.Close(); 59 sock.Dispose(); 60} 61 62}

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

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

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

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

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

jimbe

2022/12/07 10:58

送信側受信側双方のコードを出してみては如何でしょう。
TAKE_SS

2022/12/08 07:06

コメントありがとうございます。 ソースを入れてみました(Android6や7では特に問題なく動作している物です) 処理が影響しているのか、Androidのバージョンやライブラリか何かなのか。。。よく分かっていません
KOZ6.0

2022/12/08 14:38 編集

Android で動かしてみたことは無いんですが、ソース見ていて気になったところを挙げておきます。 ・AsyncStateObject ってどういう定義ですか?(だいたい予想はつきますが) ・ReceiveDataCallback は static メソッドにしたほうがいいのでは? ・Array.Resize は、毎回新しい配列を作成してコピーします。GC が頻発しそうなので、so.WkBuffer を大きめにとっておき、足りなくなったら拡張するようにしたほうが良いです。(rcvDataWk/restData を毎回確保するのも避けたほうがいいかも) ・so.Buffer を so.WkBuffer にコピーして、Buffer を使えるようになったら BeginReceive を実行しましょう。STX やら ETX, BCC 等の処理はその後で。 といったところです。 一番気になるのは Array.Resize ですかね。
TAKE_SS

2022/12/08 23:31

コメントありがとうございます AsyncStateObject の定義は追記しました。 改善の方は検討して見ます また、別の受信ロジックでも同様の事象になっているのでそちらのソースも追記しました。
KOZ6.0

2022/12/08 23:47

・こんどは SockClient の定義を貼り忘れてますね。 ・lock する意味がなさそうです。 ・sock.Close(); して sock.Dispose(); してるのだから後続の処理は発生しないのでは?
TAKE_SS

2022/12/09 03:30

Array.Resize をやめてバッファを最初から大きく取るようにしましたが、現象は変わりませんでした。 (ちょっと期待はしたのですが) Android7だと大丈夫なのに、何故かAndroid9がダメになるのが不明です。 ただ、gcが頻発は良くないでしょうから Array.Resize をやめる対応はそのままにしたいと思います。
TAKE_SS

2022/12/09 08:01

追加情報ですが、受信が来なくなった状態のまま放置していたところ、時間はみていないので不明ですが急に受信が復活する事がありました。 再オープンすればすぐに復旧するのですが、そのままでも復旧するのがよく分からない状況です
guest

回答1

0

自己解決

PC側で使用しているWifi子機を別の機器に変更したらエラーが出なくなりました。
処理の問題ではなく、子機とAndroid9又はタブレット端末の相性?なのかもしれません。
何故Android7ではOKなのかは不明ですが。

とりあえずコメント頂いた方、ありがとうございました。

投稿2022/12/13 07:38

TAKE_SS

総合スコア40

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問