2012-07-12 12 views
5

मैं कुछ घरेलू उपकरणों को जोड़ने और नियंत्रित करने के लिए एमएसडीएन के Asynchronous Client Socket कोड नमूना का उपयोग करने का प्रयास कर रहा हूं। मैं समझता हूँ के रूप में, नमूना कोड के ReceiveCallback विधि जब तक धागा एक संकेत है कि सॉकेट के डेटा के सभी रिमोट डिवाइस से प्रेषित किया गया है प्राप्त करता है EventWaitHandle ManualResetEvent का एक उदाहरण और विधि receiveDone.WaitOne() वर्तमान धागा के प्रसंस्करण धारण करने के लिए उपयोग करता है । सॉकेट के सभी डेटा प्रसारित होने के बाद (सॉकेट का डेटा खाली होता है और बाइट्स रीड = 0), वाइथंडल हटा दिया जाता है और एप्लिकेशन प्रसंस्करण जारी रहता है।एसिंक्रोनस क्लाइंट सॉकेट मैनुअल रीसेट इवेंट निष्पादन

दुर्भाग्य से, कदम के माध्यम से कोड के निष्पादन, ऐसा लगता है कि पिछली बार से है कि ग्राहक रिमोट डिवाइस से डेटा देता है के बाद, ReceiveCallback अगर डेटा कतार खाली है देखने के लिए देता है कभी नहीं (यानी bytesRead = 0), और इस तरह कभी नहीं "और"में हालत ReceiveCallback जहां ManualResetEvent के राज्य रीसेट हो गया होता और आवेदन पर कार्रवाई के लिए जारी रखा है | प्रवेश करती है। इस प्रकार, चूंकि यह "अन्यथा" स्थिति में प्रवेश नहीं करता है, मैनुअल रीसेट इवेंट कभी भी रीसेट नहीं होता है और एप्लिकेशन फ्रीज होता है।

मैं "receiveDone.WaitOne()" कोड से विधि निकाल सकते हैं हालांकि - ManualResetEvent के सूचना है कि डेटा के सभी प्राप्त हो गया है की प्रतीक्षा किए बिना निष्पादन की अनुमति; यह आमतौर पर अपूर्ण उपकरण से डेटा-स्ट्रिंग देता है।

क्या मैं इस कोड नमूना का गलत इस्तेमाल कर रहा हूं? क्या किसी ने इस मुद्दे को हल करने के बारे में पहले से देखा है या इस पर कोई अनुभव नहीं है?

7/14/2012 - अद्यतन: MSDN के Asynchronous Client Socket Example की आगे की जांच के बाद, यह स्पष्ट है कि बन गया ReceiveCallback वास्तव में-चुनाव फिर से बंदरगाह और "bytesRead = 0" शर्त पूरी होने ही जब सॉकेट जारी किया गया है (यानी क्लाइंट। शट डाउन (सॉकेटशूटडाउन। दोनों); क्लाइंट। बंद करें();)। अगर मैं इसे सही ढंग से समझता हूं, तो इसका मतलब है कि प्राप्त करने के लिए कनेक्शन को बंद करना होगा। WoneOne() विधि। यदि वेटऑन() वाइथंडल को संतुष्ट करने के लिए कनेक्शन बंद है, तो यह पूरी तरह से एप्लिकेशन के उद्देश्य को हरा देता है जिसमें मैं कनेक्शन खोलने की उम्मीद कर रहा था ताकि एप्लिकेशन उपकरण अपडेट के लिए सुन सके, जो लगातार होता है।

7/16/2012 - अद्यतन: मैं करने के लिए माइक्रोसॉफ्ट तकनीकी सहायता जो प्रतिक्रिया व्यक्त की है कि "We're doing research on this issue. It might take some time before we get back to you." जैसे, ऐसा लगता है यह प्रकट नहीं होता है कि कि इस चुनौती पर हल किया जा सकता लिखा है इस बार मालिश करने के माध्यम से इस बार।

एसिंक्रोनस क्लाइंट सॉकेट उदाहरण कोड की उपलब्धता के बिना एसिंक्रोनस संचार प्रक्रियाओं को लिखने के लिए नींव के रूप में, क्या मैं पूछ सकता हूं कि कोई भी प्रतिस्थापन दिनचर्या का सुझाव दे सकता है जो अधिक विश्वसनीय है? उपकरण के तीन टुकड़े हैं, जिनमें से प्रत्येक का अपना आईपी पता और पोर्ट नंबर है। इस प्रकार, यह आदर्श होगा यदि कक्षा का उपयोग किया जा सके, जहां प्रत्येक डिवाइस के लिए एक उदाहरण बनाया जा सकता है।इसके अतिरिक्त, बंदरगाह उपकरण द्वारा लगातार भेजे गए स्वचालित अपडेट प्राप्त करने के लिए खुला रहता है। अंत में, अद्यतनों का अंत चरित्र या परिभाषित लंबाई संकेत नहीं होता है कि संदेश का संचरण पूरा हो गया है, इस प्रकार नियमित रूप से उपलब्ध डेटा के लिए नियमित रूप से बंदरगाह को मतदान करना चाहिए। किसी भी सलाह या सुझाव की सराहना की जाएगी।

7/18/2012 - वैकल्पिक हल:MSDN के अतुल्यकालिक क्लाइंट सॉकेट कोड नमूना काम कर प्राप्त करने का प्रयास समय की एक पर्याप्त राशि खर्च करने के बाद यह स्पष्ट हो गया है कि मैं कहीं और देखने के लिए प्राप्त करने के लिए होता है कार्यक्रम द्वारा निरंतर पहचाने जाने वाले डिवाइस प्रतिक्रियाएं। किसी और को मस्तिष्क-क्षति को बचाने की उम्मीद में, मैंने उस काम को शामिल किया है जिसका उपयोग मैंने किया था जो इस बिंदु पर अच्छी तरह से काम करता है। अगर किसी के पास कोई सुझाव है, तो कृपया इस प्रश्न को जोड़ने में संकोच न करें!

// 
// ORIGINAL CODE ATTEMPT 
// 
public static Socket LutronClient; 
public static String LutronResponse = String.Empty; 
private const int LutronPort = 4999; 
private const string LutronIP = "192.168.1.71"; 
private static ManualResetEvent LutronConnectDone = new ManualResetEvent(false); 
private static ManualResetEvent LutronSendDone = new ManualResetEvent(false); 
private static ManualResetEvent LutronReceiveDone = new ManualResetEvent(false); 

private static void StartLutronClient() 
    { 
     try 
     { 
      var lutronIPAddress = IPAddress.Parse(LutronIP); 
      var lutronRemoteEP = new IPEndPoint(lutronIPAddress, LutronPort); 
      LutronClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
      LutronClient.BeginConnect(lutronRemoteEP, LutronConnectCallback, LutronClient); 
      LutronConnectDone.WaitOne(); 

      LutronSend(LutronClient, "sdl,14,100,0,S2\x0d"); 
      LutronSendDone.WaitOne(); 
      LutronReceive(LutronClient); 
      LutronReceiveDone.WaitOne(new TimeSpan(5000)); 
      MessageBox.Show("Response received from Lutron: " + LutronResponse); 
      txtBoxLutron.Text = LutronResponse; 

      LutronClient.Shutdown(SocketShutdown.Both); 
      LutronClient.Close(); 
     } 
     catch (Exception e) { MessageBox.Show(e.ToString()); } 
    } 

    private static void LutronConnectCallback(IAsyncResult lutronAr) 
    { 
     try 
     { 
      var lutronClient = (Socket)lutronAr.AsyncState; 
      lutronClient.EndConnect(lutronAr); 
      LutronConnectDone.Set(); 
     } 
     catch (Exception e) { MessageBox.Show(e.ToString()); } 
    } 

    private static void LutronReceive(Socket lutronClient) 
    { 
     try 
     { 
      var lutronState = new LutronStateObject { LutronWorkSocket = lutronClient }; 
      lutronClient.BeginReceive(lutronState.LutronBuffer, 0, LutronStateObject.BufferSize, 0, new AsyncCallback(LutronReceiveCallback), lutronState); 
     } 
     catch (Exception e) { MessageBox.Show(e.ToString()); } 
    } 

    private static void LutronReceiveCallback(IAsyncResult lutronAR) 
    { 
     try 
     { 
      var lutronState = (LutronStateObject)lutronAR.AsyncState; 
      var lutronClient = lutronState.LutronWorkSocket; 
      var bytesRead = lutronClient.EndReceive(lutronAR); 
      if (bytesRead > 0) 
      { 
       lutronState.LutronStringBuilder.AppendLine(Encoding.ASCII.GetString(lutronState.LutronBuffer, 0, bytesRead)); 
       lutronClient.BeginReceive(lutronState.LutronBuffer, 0, LutronStateObject.BufferSize, 0, new AsyncCallback(LutronReceiveCallback), lutronState); 
      } 
      else 
      { 
       if (lutronState.LutronStringBuilder.Length > 0) { LutronResponse = lutronState.LutronStringBuilder.ToString(); } 
       LutronReceiveDone.Set(); 
      } 
     } 
     catch (Exception e) { MessageBox.Show(e.ToString()); } 
    } 

    public static void LutronSend(Socket client, String data) 
    { 
     var byteData = Encoding.ASCII.GetBytes(data); 
     client.BeginSend(byteData, 0, byteData.Length, 0, LutronSendCallback, client); 
    } 

    private static void LutronSendCallback(IAsyncResult ar) 
    { 
     try 
     { 
      var client = (Socket)ar.AsyncState; 
      var bytesSent = client.EndSend(ar); 
      LutronSendDone.Set(); 
     } 
     catch (Exception e) { MessageBox.Show(e.ToString()); } 
    } 
    public class LutronStateObject 
    { 
     public Socket LutronWorkSocket; 
     public const int BufferSize = 256; 
     public byte[] LutronBuffer = new byte[BufferSize]; 
     public StringBuilder LutronStringBuilder = new StringBuilder(); 
    } 

} 

यह वह जगह है काम के आसपास मैं प्रयोग किया है:

// 
// WORK-AROUND 
// 
using System; 
using System.Windows.Forms; 

namespace _GlobalCacheInterface 
{ 
    public partial class GlobalCacheDataScreen : Form 
    { 

     //Interface objects 
     private static GC_Interface _lutronInterface; 
     private const int LutronPort = 4999; 
     private const string LutronIP = "192.168.1.71"; 
     delegate void ThreadSafeLutronCallback(string text); 

     private static GC_Interface _elanInterface; 
     private const int ElanPort = 4998; 
     private const string ElanIP = "192.168.1.70"; 
     delegate void ThreadSafeElanCallback(string text); 

     private static GC_Interface _tuneSuiteInterface; 
     private const int TuneSuitePort = 5000; 
     private const string TuneSuiteIP = "192.168.1.70"; 
     delegate void ThreadSafeTuneSuiteCallback(string text); 

     public GlobalCacheDataScreen() 
     { 
       InitializeComponent(); 

       _lutronInterface = new GC_Interface(LutronIP, LutronPort); 
       _elanInterface = new GC_Interface(ElanIP, ElanPort); 
       _tuneSuiteInterface = new GC_Interface(TuneSuiteIP, TuneSuitePort); 

      // Create event handlers to notify application of available updated information. 
      _lutronInterface.DataAvailable += (s, e) => ThreadSafeTxtBoxLutron(_lutronInterface._returnString); 
      _elanInterface.DataAvailable += (s, e) => ThreadSafeTxtBoxElan(_elanInterface._returnString); 
      _tuneSuiteInterface.DataAvailable += (s, e) => ThreadSafeTxtBoxTuneSuite(_tuneSuiteInterface._returnString); 
      _lutronInterface.Connected += (s, e) => UpdateUI(); 
      _elanInterface.Connected += (s, e) => UpdateUI(); 
      _tuneSuiteInterface.Connected += (s, e) => UpdateUI(); 

      UpdateUI(); 
     } 

     private void UpdateUI() 
     { 
      _buttonConnectToLutron.Enabled = !_lutronInterface._isConnected; 
      _buttonConnectToElan.Enabled = !_elanInterface._isConnected; 
      _buttonConnectToTuneSuite.Enabled = !_tuneSuiteInterface._isConnected; 
      _buttonDisconnectFromLutron.Enabled = _lutronInterface._isConnected; 
      _buttonDisconnectFromElan.Enabled = _elanInterface._isConnected; 
      _buttonDisconnectFromTuneSuite.Enabled = _tuneSuiteInterface._isConnected; 
      string connectLutronStatus = _lutronInterface._isConnected ? "Connected" : "Not Connected"; 
      string connectElanStatus = _elanInterface._isConnected ? "Connected" : "Not Connected"; 
      string connectTuneSuiteStatus = _tuneSuiteInterface._isConnected ? "Connected" : "Not Connected"; 
      _textBoxLutronConnectStatus.Text = connectLutronStatus; 
      _textBoxElanConnectStatus.Text = connectElanStatus; 
      _textBoxTuneSuiteConnectStatus.Text = connectTuneSuiteStatus; 
     } 


     private void ThreadSafeTxtBoxLutron(string message) { if (_lutronRichTextRxMessage.InvokeRequired) { var d = new ThreadSafeLutronCallback(ThreadSafeTxtBoxLutron); _lutronRichTextRxMessage.Invoke(d, new object[] { message }); } else { _lutronRichTextRxMessage.Text = message; } }  
     private void ThreadSafeTxtBoxElan(string message) { if (_elanRichTextRxMessage.InvokeRequired) { var d = new ThreadSafeElanCallback(ThreadSafeTxtBoxElan); _elanRichTextRxMessage.Invoke(d, new object[] { message }); } else { _elanRichTextRxMessage.Text = message; if (message.EndsWith("\r")) { MessageBoxEx.Show(message, "Message from Lutron Elan", 1000); } } } 
     private void ThreadSafeTxtBoxTuneSuite(string message) { if (_tuneSuiteRichTextRxMessage.InvokeRequired) { var d = new ThreadSafeTuneSuiteCallback(ThreadSafeTxtBoxTuneSuite); _tuneSuiteRichTextRxMessage.Invoke(d, new object[] { message }); } else { _tuneSuiteRichTextRxMessage.Text = message; if (message.EndsWith("\r")) { MessageBoxEx.Show(message, "Message from TuneSuite", 1000); } } } 

     private void _buttonConnectToLutron_Click(object sender, EventArgs e) { _lutronInterface.Connect(); } 
     private void _buttonDisconnectFromLutron_Click(object sender, EventArgs e) { _lutronInterface.Disconnect(); } 
     private void _buttonConnectToElan_Click(object sender, EventArgs e) { _elanInterface.Connect(); } 
     private void _buttonDisconnectFromElan_Click(object sender, EventArgs e) { _elanInterface.Disconnect(); } 
     private void _buttonConnectToTuneSuite_Click(object sender, EventArgs e) { _tuneSuiteInterface.Connect(); } 
     private void _buttonDisconnectFromTuneSuite_Click(object sender, EventArgs e) { _tuneSuiteInterface.Disconnect(); } 
     private void _buttonLutronSendMessage_Click(object sender, EventArgs e) { _lutronInterface.SendCommand(_lutronRichTextTxMessage.Text); } 
     private void _buttonElanSendMessage_Click(object sender, EventArgs e) { _elanInterface.SendCommand(_elanRichTextTxMessage.Text); } 
     private void _buttonTuneSuiteSendMessage_Click(object sender, EventArgs e) { _tuneSuiteInterface.SendCommand(_elanRichTextTxMessage.Text); } 
     private void _buttonLightOn_Click(object sender, EventArgs e) { _lutronInterface.SendCommand("sdl,14,100,0,S2"); } 
     private void _buttonLightOff_Click(object sender, EventArgs e) { _lutronInterface.SendCommand("sdl,14,0,0,S2"); } 
     private void _buttonStereoOnOff_Click(object sender, EventArgs e) { _elanInterface.SendCommand("sendir,4:3,1,40000,4,1,21,181,21,181,21,181,21,181,21,181,21,181,21,181,21,181,21,181,21,181,21,181,21,800"); } 
     private void _button30_Click(object sender, EventArgs e) { _tuneSuiteInterface.SendCommand("\xB8\x4D\xB5\x33\x30\x00\x30\x21\xB8"); } 
     private void _button31_Click(object sender, EventArgs e) { _tuneSuiteInterface.SendCommand("\xB8\x4D\xB5\x33\x31\x00\x30\x21\xB8"); } 
     private void _button26_Click(object sender, EventArgs e) { _tuneSuiteInterface.SendCommand("\xB8\x4D\xB5\x32\x36\x00\x30\x21\xB8"); } 
    } 
} 

और GC_Interface वर्ग:

using System; 
using System.Net; 
using System.Net.Sockets; 
using System.Text; 
using System.Windows.Forms; 

namespace _GlobalCacheInterface 
{ 
    class GC_Interface 
    { 
     // Declare an event handler to notify when updates are available. 
     public event EventHandler<EventArgs> DataAvailable; 
     public string _returnString = ""; 

     // Declare an event handler to notify status of connection. 
     public event EventHandler<EventArgs> Connected; 
     public bool _isConnected; 

     public AsyncCallback ReceiveCallback; 
     public Socket Client; 
     private string _ipAddress; 
     private int _port; 
     private bool _waitForEndCharacter; 
     private byte _endCharacter; 
     byte[] m_DataBuffer = new byte[10]; 
     IAsyncResult m_Result; 

     public GC_Interface(string ipAddress, int port) { Init(ipAddress, port, false, 0); } 

     private void Init(string ipAddress, int port, bool waitForEndCharacter, byte endCharacter) 
     { 
      _ipAddress = ipAddress; 
      _port = port; 
      _waitForEndCharacter = waitForEndCharacter; 
      _endCharacter = endCharacter; 
      _isConnected = false; 
     } 

     public bool Connect() 
     { 
      try 
      { 
       // Create a TCP/IP socket. 
       Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 

       // Establish the remote endpoint for the socket. 
       var address = IPAddress.Parse(_ipAddress); 
       var remoteEP = new IPEndPoint(address, _port); 

       // Connect to the remote endpoint. 
       Client.Connect(remoteEP); 
       if (Client.Connected) 
       { 
        _isConnected = true; 
        ConnectedEventHandler(); 
        WaitForData(); 
       } 
       return true; 
      } 
      catch (SocketException se) { MessageBox.Show("\n connection failed, is the server running?\n" + se.Message); return false; } 
     } 
     public bool SendCommand(string command) 
     { 
      try 
      { 
       // Convert the string data to byte data using ASCII encoding. 
       var byteData = Encoding.Default.GetBytes(command); 
       // Add a carraige-return to the end. 
       var newArray = new byte[byteData.Length + 1]; 
       byteData.CopyTo(newArray, 0); 
       newArray[newArray.Length - 1] = 13; 
       if (Client == null) { return false; } 
       Client.Send(newArray); 
       return true; 
      } 
      catch (SocketException se) { MessageBox.Show(se.Message); return false; } 
     } 
     public void WaitForData() 
     { 
      try 
      { 
       if (ReceiveCallback == null) { ReceiveCallback = new AsyncCallback(OnDataReceived); } 
       var theSocPkt = new SocketPacket { thisSocket = Client }; 
       m_Result = Client.BeginReceive(theSocPkt.DataBuffer, 0, theSocPkt.DataBuffer.Length, SocketFlags.None, ReceiveCallback, theSocPkt); 
      } 
      catch (SocketException se) { MessageBox.Show(se.Message); } 
     } 
     public class SocketPacket 
     { 
      public System.Net.Sockets.Socket thisSocket; 
      public byte[] DataBuffer = new byte[1]; 
     } 
     public void OnDataReceived(IAsyncResult asyn) 
     { 
      try 
      { 
        SocketPacket theSockId = (SocketPacket)asyn.AsyncState; 
       var iRx = theSockId.thisSocket.EndReceive(asyn); 
       char[] Chars = new char[iRx + 1]; 
       System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder(); 
       int CharLen = d.GetChars(theSockId.DataBuffer, 0, iRx, Chars, 0); 
       System.String szData = new System.String(Chars); 
       _returnString = _returnString + szData.Replace("\0", ""); 
       // When an update is received, raise DataAvailable event 
       DataAvailableEventHandler(); 
       WaitForData(); 
      } 
      catch (ObjectDisposedException) { System.Diagnostics.Debugger.Log(0, "1", "\nOnDataReceived: Socket has been closed\n"); } 
      catch (SocketException se) { MessageBox.Show(se.Message); } 
     } 
     public bool Disconnect() 
     { 
       try 
       { 
        if (Client == null) { return false; } 
        Client.Close(); 
        Client = null; 
        _isConnected = false; 
        return true; 
       } 
       catch (Exception) { return false; } 
     } 
     protected virtual void DataAvailableEventHandler() 
     { 
      var handler = DataAvailable; 
      if (handler != null) { handler(this, EventArgs.Empty); } 
     } 
     protected virtual void ConnectedEventHandler() 
     { 
      var handler = Connected; 
      if (handler != null) { handler(this, EventArgs.Empty); } 
     } 

    } 
} 

उत्तर

4

मुझे एक ही समस्या थी, मेरी समस्या को हल करने वाले कोड में एक उपलब्ध चेक जोड़ना। नीचे संशोधित कोड है।

private static void ReceiveCallback(IAsyncResult ar) { 
     try { 
      StateObject state = (StateObject) ar.AsyncState; 
      Socket client = state.workSocket; 

      int bytesRead = client.EndReceive(ar); 
      if (bytesRead > 0) { 
       state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead)); 
       // Check if there is anymore data on the socket 
       if (client.Available > 0) { 
        client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state); 
       } 
      } 

      if (bytesRead == 0 || client.Available == 0) { 
       if (state.sb.Length > 1) { 
        response = state.sb.ToString(); 
       } 
       receiveDone.Set(); 
      } 
     } catch (Exception e) { 
      Console.WriteLine(e.ToString()); 
     } 
    } 

आशा है कि मदद करता है।

+0

जेएफगन - आपकी सहायता के लिए धन्यवाद। – Bill

1

मैं यहाँ सवाल sidestepping कर रहा हूँ। मैं आपको जो चाहिए उसे जवाब देने का प्रयास करता हूं, न कि आप जो पूछते हैं:

सिंक्रोनस कोड का उपयोग करें। यह समझना आसान होगा, आपको कॉलबैक या घटनाओं की आवश्यकता नहीं है। इसके अलावा, कम धागे की गणना के लिए, यह बेहतर प्रदर्शन करने की संभावना है।

आप अपने वर्तमान कोड में मौजूद बग से भी बचते हैं। यदि कोई अपवाद होता है तो आपकी गणना कभी पूर्ण नहीं होती है। सिंक्रोनस कोड में वह समस्या नहीं है।

संबंधित मुद्दे