简体   繁体   English

Arduino以太网C#客户端未接收到数据

[英]Arduino ethernet c# client not receiving data

I am having a problem receiving data (a string of text) from an Arduino via a C# Winform app. 我在通过C#Winform应用程序从Arduino接收数据(文本字符串)时遇到问题。 The sketch on the Arduino basically reply with whatever I send. Arduino上的草图基本上可以用我发送的内容进行回复。 I am able to send data. 我能够发送数据。 What is strange is that if I telnet the device and type any text it responds correctly so it appears the problem is my C# code, however, I can't seem to figure out where I am incorrect. 奇怪的是,如果我对设备进行telnet并输入任何可正确响应的文本,那么看来问题出在我的C#代码上,但是,我似乎无法弄清楚我的错误所在。

Here is what I have 这是我所拥有的

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);
        }
    ));
    }


}

Here is part of the Arduino sketch 这是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;
   }      
}
}
}

Your code has a number of things wrong with it, including what has to be the most common novice error I've seen in any context: you fail to take into account the number of bytes actually read . 您的代码有很多问题,包括我在任何情况下看到的最常见的新手错误:您没有考虑实际读取的字节数。 Plus you have another common variation on the theme, which is that you process the entire receive buffer array as if the whole thing had valid data in it. 另外,您在主题上还有另一个共同的变体,那就是您像处理整个接收缓冲区阵列中的有效数据一样处理整个接收缓冲区阵列。

Without a way to test, it's hard to know for sure. 没有测试的方法,很难确定。 But at the very least, you should change your receive method to look like this: 但是至少,您应该将接收方法更改为如下所示:

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();
    }
}
  • DON'T pointlessly nest a while (true) loop inside another while (true) loop 切勿毫无意义巢while (true)另一个内部循环while (true)
  • DON'T create a new NetworkStream every time you want to read 每次阅读时都不要创建新的NetworkStream
  • DON'T concern yourself with the Socket.ReceiveBufferSize property value 与关心自己Socket.ReceiveBufferSize属性值
  • DO capture and use the return value from the read operation 必须捕获并使用读取操作中的返回值
  • DON'T concatenate the empty string with other strings (even in an iterated scenario, one should be using StringBuilder instead, and here you're not even iterating the concatenation!) 不要将空字符串与其他字符串连接在一起(即使在迭代的情况下,也应该使用StringBuilder ,并且这里甚至没有迭代连接!)

Of course, not all of those flaws are fatal. 当然,并非所有这些缺陷都是致命的。 The biggest issues are the new NetworkStream on each read and the mismanagement of the receive buffer and result value. 最大的问题是每次读取都需要新的NetworkStream以及接收缓冲区和结果值的管理不当。 But really, you should strive for all of the code to be good. 但实际上,您应该努力使所有代码都变得更好。

Note that the above merely improves the code. 注意,以上仅改进了代码。 Even the above still has a variation on "the most common novice error I've seen in any context": while it does use the return value from the read operation, it does not do everything with it that it should. 即使以上内容仍对“我在任何情况下都遇到过的最常见的新手错误”有所不同:尽管它确实使用了读取操作的返回值,但并没有尽其所能。 In particular: 尤其是:

  1. You are not actually guaranteed that you will receive all of the bytes that were sent to you in one read operation. 实际上,不能保证您将通过一次读取操作接收到发送给您的所有字节。 This means your application protocol really should have some way for you to identify within the stream of bytes you're reading where one message ends and the next one starts. 这意味着您的应用程序协议确实应该有某种方式可以让您在正在读取的字节流中识别一条消息的结尾和下一条消息的开始。
  2. When the connection is gracefully closed, the read operation will return 0 as the byte count, at which point your own code is supposed to respond by finishing up whatever writes to the socket you need to (if any) and then gracefully closing your own socket by calling Socket.Shutdown(SocketShutdown.Both) and finally Socket.Close() . 当连接正常关闭时,读取操作将返回0作为字节数,这时您自己的代码应该通过完成对套接字的所有写操作(如果有)来响应,然后优雅地关闭自己的套接字通过调用Socket.Shutdown(SocketShutdown.Both)并最终Socket.Close()

But the above should at least help you make forward progress in your project. 但是以上内容至少应该帮助您在项目中取得进步。

One other thing you really should change IMHO which I didn't bother in the above, is that you should not use an instance field (ie readData ) to pass data when simply passing it as a method parameter would suffice. 您确实应该更改IMHO的另一件事,而我在上面没有打扰,那就是当简单地将它作为方法参数就足够时,您不应使用实例字段(即readData )来传递数据。 You should avoid side-effects in your code as much as possible. 您应该尽可能避免代码中的副作用 It will make the code much easier to comprehend and thus to write correctly, among other things. 这将使代码更易于理解,从而可以正确编写代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM