2016-06-01 3 views
0

私はC#アプリケーションでBeginSendとBeginReceiveの両方を使用しています。これはクライアントリスナーであり、サーバーからのみデータを受信します。私はBeginReceiveを使ってデータを取得しています。C#ソケット接続のBeginSendとBeginReceiveの問題

しかし、受信を行うだけでは接続を生き生きとして安定に保つことができないことがわかりました。だから、私は、BeginSendを使って接続を維持するために、私のアプリケーションで常にサーバにpingすることを決めました。以下は

は私のコードです:

private void timer1_Tick(object sender, EventArgs e) 
{ 
    DataProcess(); 
} 

public Socket _serverSocket = null; 
private byte[] _recieveBuffer = new byte[128]; 
byte[] AllBytes; 
void DataProcess() 
{ 
    //TimeSpan ts; 
    try 
    { 
     //Thread.Sleep(100); 
     if (_serverSocket == null || sockState == MySocketState.Disconnected) 
     { 
      Console.WriteLine("Trying to connect..."); 
      SetupServer(); 
     } 
     else 
     { 
      AllBytes = ASCIIEncoding.ASCII.GetBytes(COM_DeviceIsOnline); 
      _serverSocket.BeginSend(AllBytes, 0, AllBytes.Length, SocketFlags.None, new AsyncCallback(SendCallback), null); 
     } 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine(ex.ToString()); 
    } 
} 

private void SetupServer() 
{ 
    try 
    { 
     _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
     _serverSocket.Connect(_sIP, Int32.Parse(_sPort)); 
    } 
    catch (SocketException ex) 
    { 
     Console.WriteLine(ex.Message); 
    } 

    if (_serverSocket.Connected) 
    { 
     sockState = MySocketState.Connected; 
     browser.ExecuteScriptAsync("svrConnect();"); 
     Console.WriteLine("Server connected..."); 
     _serverSocket.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), null); 
    } 
} 

void SendCallback(IAsyncResult ar) 
{ 
    try 
    { 
     int bytesSent = _serverSocket.EndSend(ar); 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine(ex.ToString()); 
    } 
} 

private void ReceiveCallback(IAsyncResult AR) 
{ 
    try 
    { 
     if (_serverSocket == null) 
      _serverSocket = (Socket)AR.AsyncState; 

     //Check how much bytes are recieved and call EndRecieve to finalize handshake 
     int recieved = _serverSocket.EndReceive(AR); 

     if (recieved <= 0) 
     { 
      CloseSocket(); 
      return; 
     } 

     //Copy the recieved data into new buffer , to avoid null bytes 
     byte[] recData = new byte[recieved]; 
     Buffer.BlockCopy(_recieveBuffer, 0, recData, 0, recieved); 
     string strData = ASCIIEncoding.ASCII.GetString(recData); 
     Console.WriteLine(strData); 

     //Process data here the way you want , all your bytes will be stored in recData 

     int nSOHPos = -1; 
     int nSTXPos = -1; 
     int nETXPos = -1; 
     int nEOTPos = -1; 

     nSOHPos = Array.IndexOf(recData, SOH); 
     nSTXPos = Array.IndexOf(recData, STX); 
     nETXPos = Array.IndexOf(recData, ETX); 
     nEOTPos = Array.IndexOf(recData, EOT); 

     if ((nSOHPos == -1) || (nSTXPos == -1) || (nETXPos == -1) || (nEOTPos == -1)) 
     { 
      CloseSocket(); 
      return; 
     } 

     if (nSOHPos > nSTXPos || 
       nSTXPos > nETXPos || 
       nETXPos > nEOTPos) 
     { 
      CloseSocket(); 
      return; 
     } 

     if ((nETXPos - nSTXPos) < 6) 
     { 
      CloseSocket(); 
      return; 
     } 

     string _sCommand = ASCIIEncoding.ASCII.GetString(recData, nSTXPos + 6, 2); 

     if ((_sCommand == "CN") || (_sCommand == "CL") || (_sCommand == "CR")) 
     { 
      nDept = int.Parse(ASCIIEncoding.ASCII.GetString(recData, nSTXPos + 12, 2)); 
      if (nDept != dept_id) return; 
      nCntr = int.Parse(ASCIIEncoding.ASCII.GetString(recData, nSTXPos + 14, 2)); 
      nServ = int.Parse(ASCIIEncoding.ASCII.GetString(recData, nSTXPos + 16, 2)); 
      sQnum = ASCIIEncoding.ASCII.GetString(recData, nSTXPos + 8, 4); 
      string[] sSplit = strData.Split('^'); 
      string sCusName = sSplit[1]; 
      //if (_sCommand == "CR") sCusName = " "; 
      Console.WriteLine("Dept ID = " + nDept); 
      Console.WriteLine("Cntr ID = " + nCntr); 
      Console.WriteLine("Serv ID = " + nServ); 
      Console.WriteLine("Queue No = " + sQnum); 
      Console.WriteLine("Cus Name = " + sCusName); 
      var script = string.Format("nextCall(\'{0}\', {1}, {2});", sQnum, nCntr, nServ); 
      browser.ExecuteScriptAsync(script); 
     } 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine(ex.ToString()); 
     CloseSocket(); 
    } 
    finally 
    { 
     try 
     { 
      //Start receiving again 
      if (_serverSocket != null) 
       _serverSocket.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), null); 
      //theDevSock.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, ReceiveCallback, theDevSock); 
     } 
     catch (Exception ex2) 
     { } 
    } 
} 

public void CloseSocket() 
{ 
    try 
    { 
     if (_serverSocket != null) 
     { 
      if (_serverSocket.Connected) 
       _serverSocket.Shutdown(SocketShutdown.Both); 
      _serverSocket.Close(); 
     } 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine(ex.ToString()); 
    } 
    _serverSocket = null; 
    sockState = MySocketState.Disconnected; 
    browser.ExecuteScriptAsync("svrDisconnect();"); 
} 

私のアプリケーションは、私は、サーバーへの接続を開始します。サーバーに接続すると、サーバーのpingが開始されます。しかし、BeginSendを使用してサーバーにpingを実行するたびに、「スレッド0x1ff0がコード259(0x103)で終了しました」というエラーが発生しました。サーバーへの接続が切断され、アプリケーションがサーバーへの接続を再試行します。その後、正常に接続した後、再度pingを実行すると、再び切断されます。

私のコーディングは正しく書かれていますか?このようなBeginSendをpingサーバーに使用できますか?

+0

'SetSocketOption'メソッドを使用して接続を維持するには、次のようにします:' socket.SetSocketOption(SocketOptionLevel.Tcp、SocketOptionLevel.Tcp、SocketOptionName.KeepAlive、true); ' – raidensan

+0

このコーディングの行はどこに追加しますか?お勧めできますか? – Coolguy

+0

これは本当にあなたのアプリケーションのロジックに依存しますが、一般的なアプローチは接続する前にソケットオプションを設定することです。 – raidensan

答えて

0

私にpingを送信するには、以下のコードを追加しました:

 private void timer2_Tick(object sender, EventArgs e) 
    { 
     pingServer(); 
    } 

    void pingServer() 
    { 
     if (_serverSocket != null || sockState == MySocketState.Connected) 
     { 
      Console.WriteLine("Ping Server"); 
      AllBytes = ASCIIEncoding.ASCII.GetBytes(COM_DeviceIsOnline); 
      //_serverSocket.BeginSend(AllBytes, 0, AllBytes.Length, SocketFlags.None, new AsyncCallback(SendCallback), null); 
      SendTCPData(0x01, 1, 1, 1, "AA", ""); 
     } 
    } 

    public bool SendTCPData(byte bySequenceNo, int nSlaveID, int nDeviceID, 
          int nStatus, String strCommand, String strData) 
    { 
     return SendTCPData(ACK, bySequenceNo, nSlaveID, nDeviceID, nStatus, strCommand, strData); 
    } 

    public bool SendTCPData(byte byTypeCode, byte bySequenceNo, 
          int nSlaveID, int nDeviceID, 
          int nStatus, String strCommand, 
          String strData) 
    { 
     return SendTCPData(byTypeCode, bySequenceNo, nSlaveID, nDeviceID, 
          nStatus, strCommand, strData, 0); 
    } 

    public bool SendTCPData(byte byTypeCode, byte bySequenceNo, 
          int nSlaveID, int nDeviceID, 
          int nStatus, String strCommand, String strData, int nProtocolType) 
    { 
     byte[] AllBytes; 
     String strTemp; 
     try 
     { 
      strTemp = nSlaveID.ToString("0#") + 
       nDeviceID.ToString("0#") + 
       nStatus.ToString() + 
       strCommand + strData; 

      if (nProtocolType == 0) 
      { 

       AllBytes = new byte[strTemp.Length + 7]; 
       AllBytes[0] = SOH; 
       AllBytes[1] = byTypeCode; 
       AllBytes[2] = (byte)((int)bySequenceNo | 0x80); 
       AllBytes[3] = STX; 
       ASCIIEncoding.ASCII.GetBytes(strTemp).CopyTo(AllBytes, 4); 
       AllBytes[AllBytes.Length - 3] = ETX; 
       AllBytes[AllBytes.Length - 2] = 128; 
       AllBytes[AllBytes.Length - 1] = EOT; 
      } 
      else 
      { 
       AllBytes = new byte[strTemp.Length + 6]; 
       AllBytes[0] = SOH; 
       AllBytes[1] = STX; 
       ASCIIEncoding.ASCII.GetBytes(strTemp).CopyTo(AllBytes, 2); 
       AllBytes[AllBytes.Length - 4] = ETX; 
       AllBytes[AllBytes.Length - 3] = ETX; 
       AllBytes[AllBytes.Length - 2] = 128; 
       AllBytes[AllBytes.Length - 1] = EOT; 
      } 
      //Debug.WriteLine("Sending data to " + _sIPAddr + " -> " + ASCIIEncoding.ASCII.GetString(AllBytes)); 
      return SendByte(AllBytes, AllBytes.Length); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex.ToString()); 
     } 
     return false; 

    } 

    public bool SendByte(byte[] pByteData, int nLength) 
    { 
     try 
     { 
      if (_serverSocket == null) return false; 
      if (!_serverSocket.Connected) return false; 
      Console.WriteLine("SendByte = " + ASCIIEncoding.ASCII.GetString(pByteData, 0, nLength)); 
      //Debug.WriteLine("SendByte Length= " + nLength.ToString()); 
      _serverSocket.BeginSend(pByteData, 0, nLength, SocketFlags.None, 
       SendCallback, _serverSocket); 
      //dtLastActivity = DateTime.Now; 
      return true; 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex.ToString()); 
      CloseSocket(); 

     } 
     return false; 
    } 

私がいる限り、それはサーバとの接続を持っているとして、それがpingを送信しますので、PINGを送信するために30秒のタイマーを使用しています。今、それはすでにケーブルの抜けを検出することができます。

あなたはこの回答についてどう思いますか?

+0

ちょうど私のアプリは、デバッグモードでは、時々 "スレッド0xはコード259で終了している"と表示されます、pingコードを追加した後。これは、pingコードを追加する前に発生しません。これは心配ですか? – Coolguy