【问题标题】:Arduino ethernet c# client not receiving dataArduino 以太网 C# 客户端未接收数据
【发布时间】:2014-12-07 07:34:18
【问题描述】:

我在通过 C# Winform 应用程序从 Arduino 接收数据(文本字符串)时遇到问题。 Arduino 上的草图基本上会回复我发送的任何内容。我能够发送数据。奇怪的是,如果我 telnet 设备并键入它正确响应的任何文本,那么问题似乎出在我的 C# 代码上,但是,我似乎无法弄清楚我错在哪里。

这就是我所拥有的

public partial class Form1 : Form
{

    System.Net.Sockets.TcpClient clientSocket = new System.Net.Sockets.TcpClient();
    NetworkStream serverStream = default(NetworkStream);
    string readData = null;


    public Form1()
    {
        InitializeComponent();

    }

    private void button1_Click(object sender, EventArgs e)
    {
        byte[] outStream = System.Text.Encoding.ASCII.GetBytes(textBox2.Text);
        serverStream.Write(outStream, 0, outStream.Length);
        serverStream.Flush();
    }


    private void button2_Click(object sender, EventArgs e)
    {

        clientSocket.Connect("192.168.1.177", 5223);
        readData = "Conected Arduino ...";
        msg();
        serverStream = clientSocket.GetStream();
        byte[] outStream = System.Text.Encoding.ASCII.GetBytes(textBox2.Text);
        serverStream.Write(outStream, 0, outStream.Length);
        serverStream.Flush();

        Thread ctThread = new Thread(getData);
        ctThread.Start();
    }



    private void getData()
    {

        while (true)
        {

            while (true)
            {
                serverStream = clientSocket.GetStream();
                int buffSize = clientSocket.ReceiveBufferSize;
                byte[] inStream = new byte[10025];
                serverStream.Read(inStream, 0, buffSize);
                string returndata = System.Text.Encoding.ASCII.GetString(inStream);
                readData = "" + returndata;
                msg();
            }

        }
    }

    private void msg()
    {

        this.BeginInvoke(new Action(() =>
        {
            textBox1.Text = String.Format("{0}{1} >> {2}", textBox1.Text, Environment.NewLine, readData);
        }
    ));
    }


}

这是 Arduino 草图的一部分

void loop() {
// wait for a new client:
EthernetClient client = server.available();

// when the client sends the first byte, say hello:
if (client) {
if (!alreadyConnected) {
  // clead out the input buffer:
  client.flush();    
  Serial.println("We have a new client");
  client.println("Hello, client!");
  alreadyConnected = true;
}

if (client.available() > 0) {
  // read the bytes incoming from the client:
  char thisChar = client.read();
  // echo the bytes back to the client:
  //server.write(thisChar);
  // echo the bytes to the server as well:
  //Serial.write(thisChar);
   if (inputPos < maxLength-1) 
   { 
    if (thisChar == '\n') 
        {
            inputString[inputPos] = 0;
                            server.write(inputString);
            Serial.write(inputString);
            inputPos = 0;
        } else {
                // add it to the inputString:
            inputString[inputPos] = thisChar;
            inputPos++;
        }
   } else {
     inputPos = 0;
   }      
}
}
}

【问题讨论】:

    标签: c# network-programming arduino ethernet


    【解决方案1】:

    你的代码有很多问题,包括我在任何情况下见过的最常见的新手错误:你没有考虑到实际读取的字节数。另外,您在主题上还有另一个常见的变体,即您处理整个接收缓冲区数组,就好像整个事物中有有效数据一样。

    没有测试方法,很难确定。但至少,您应该将接收方法更改为如下所示:

    private void getData()
    {
        serverStream = clientSocket.GetStream();
    
        while (true)
        {
            byte[] inStream = new byte[10025];
            int bytesRead = serverStream.Read(inStream, 0, inStream.Length);
            readData = System.Text.Encoding.ASCII.GetString(inStream, 0, bytesRead);
            msg();
        }
    }
    
    • 不要while (true) 循环嵌套在另一个while (true) 循环中
    • 不要在每次您想阅读时创建一个新的NetworkStream
    • 不要关注Socket.ReceiveBufferSize 属性值
    • 捕获并使用读取操作的返回值
    • 不要将空字符串与其他字符串连接(即使在迭代场景中,也应该使用StringBuilder,而在这里你甚至没有迭代连接!)

    当然,并非所有这些缺陷都是致命的。最大的问题是每次读取时新的NetworkStream 以及接收缓冲区和结果值的管理不善。但实际上,您应该努力使所有代码都很好。

    请注意,以上只是改进了代码。即使上面的内容仍然存在“我在任何情况下看到的最常见的新手错误”的变体:虽然它确实使用了读取操作的返回值,但它并没有做它应该做的所有事情。特别是:

    1. 实际上并不能保证您将收到在一次读取操作中发送给您的所有字节。这意味着您的应用程序协议确实应该有某种方式让您在正在读取的字节流中识别一条消息结束和下一条消息的开始位置。
    2. 当连接正常关闭时,读取操作将返回 0 作为字节数,此时您自己的代码应该通过完成对套接字的任何写入来响应(如果有的话)然后正常关闭调用Socket.Shutdown(SocketShutdown.Both),最后调用Socket.Close(),创建您自己的套接字。

    但以上内容至少应该可以帮助您在项目中取得进展。

    您真正应该更改恕我直言的另一件事,我在上面没有打扰,就是您不应该使用实例字段(即readData)来传递数据,而只需将其作为方法参数传递就足够了。你应该尽可能避免side-effects in your code。这将使代码更容易理解,从而更容易正确编写。

    【讨论】:

      猜你喜欢
      • 2018-06-18
      • 1970-01-01
      • 1970-01-01
      • 2017-03-13
      • 2020-02-05
      • 2019-03-30
      • 1970-01-01
      • 2015-12-21
      • 1970-01-01
      相关资源
      最近更新 更多