我的C++客户端套接字代码只收集由Arduino套接字服务器提供的输出的第一行(我猜我可以这样称呼它)。请告诉我我的C++代码出了什么问题,如何修复?如果问题太冗长,请跳到底部的C++代码。
硬件设置:带有以太网卡(盾牌)的Arduino Mega和带有Ubuntu 16.04的Intel NUC。两个设备使用电缆和未管理的交换机连接。 Arduino端:我从Arduino Ethernet库中的一个Web服务器示例开始,修改了代码,直到我能够收集所有I/O的状态,处理I/O数据,并向Web客户端提供结果。下面的图片显示了我的Arduino输出的HTML快照。
硬件设置:带有以太网卡(盾牌)的Arduino Mega和带有Ubuntu 16.04的Intel NUC。两个设备使用电缆和未管理的交换机连接。 Arduino端:我从Arduino Ethernet库中的一个Web服务器示例开始,修改了代码,直到我能够收集所有I/O的状态,处理I/O数据,并向Web客户端提供结果。下面的图片显示了我的Arduino输出的HTML快照。
![enter image description here](https://istack.dev59.com/2QSgl.webp)
处理套接字服务器端的Arduino代码如下(一切正常,但考虑到显示所有内容而包括):
#include <SPI.h>
#include <Ethernet.h>
byte mac[] = {0xBA, 0xDA, 0x55, 0x12, 0x34, 0x56};
IPAddress ip(192, 168, 0, 21);
EthernetServer server(80);
void setup()
{
Ethernet.begin(mac, ip);
// Check for Ethernet hardware present
if (Ethernet.hardwareStatus() == EthernetNoHardware)
{
Serial.println("Ethernet shield was not found. Sorry, can't run without hardware.");
while (true)
{
delay(1); // do nothing, no point running without Ethernet hardware
}
}
if (Ethernet.linkStatus() == LinkOFF)
{
Serial.println("Ethernet cable is not connected.");
}
server.begin();
}
void loop()
{
//true when there is an incoming connection
if (client)
{
Serial.println("new client");
// an http request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected())
{
if (client.available())
{
//the next two lines print the client HTTP GET request to serial.
char c = client.read();
Serial.write(c);
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank)
{
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println("Refresh: 1");
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
//whole bunch of client.println("...."); to dish out a web page.
client.println("</html>");
break;
}
if (c == '\n')
{
// you're starting a new line
currentLineIsBlank = true;
} else if (c != '\r')
{
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
//delay(1);
// close the connection:
client.stop();
Serial.println("client disconnected");
}
}
使用Ubuntu 16.04和C++11的Intel NUC:我一直在跟随教程(https://www.binarytides.com/socket-programming-c-linux-tutorial/)学习套接字客户端,并从https://www.learncpp.com学习C++。到目前为止,我能够使用套接字向Google服务器发送请求并收集HTML页面,并将HTML打印到终端上:
![enter image description here](https://istack.dev59.com/bqMLg.webp)
这是我的C++代码:
#include <iostream> //for std::cout & std::endl
#include<arpa/inet.h> //inet_addr
#include<string.h> // for strlen
int main()
{
int my_socket = socket(AF_INET , SOCK_STREAM , 0);
//make sure the socket we got is OK
if (my_socket == -1)
{
std::cout << "problem creating a socket." << std::endl;
}
struct sockaddr_in connectionToServer;
connectionToServer.sin_addr.s_addr = inet_addr("172.217.2.99");//google IP
connectionToServer.sin_family = AF_INET; //type of IP addres. where AF_INET is IPv4
connectionToServer.sin_port = htons(80); //port is set via a method
if (connect(my_socket , (struct sockaddr *)&connectionToServer , sizeof(connectionToServer)) < 0)
{
std::cout << "connect error" << std::endl;
return 1;
}
std::cout << "Connected" << std::endl;
//send a request to get a page
char *message = "GET / HTTP/1.1\r\n\r\n";
if( send(my_socket , message , strlen(message) , 0) < 0)
{
std::cout << "Send failed" << std::endl;
return 1;
}
std::cout << "Data Sent\n" << std::endl;
char buffer [20000] = {};
if( recv(my_socket, buffer , sizeof(buffer) , 0) < 0)
{
std::cout << "recv failed" << std::endl;
}
for(int i=0; i<20000 ; i++)
{
std::cout<< buffer[i];
}
return 0;
}
问题:当我将C++程序中的IP地址从Google更改为我的Arduino时,cpp客户端套接字程序只收集Arduino套接字服务器输出的第一行。我知道它是第一行,因为我修改了Arduino服务器输出的第一行,添加了“..但这并不重要”,并且更改显示在c ++程序的标准输出窗口中。我需要C++程序收集整个输出,而不仅仅是第一行。我真的无法弄清楚如何做到这一点。
请问您能帮我解决以下问题吗:
- 如何收集完整的Arduino消息(而不仅仅是第一行)?我需要对我的C++程序进行哪些修改?该系统需要能够将数据从一个设备传递到另一个设备。
- 整个设置的目标是从Arduino传递2个浮点数和6个整数到我的C++程序中。很快我将放弃整个HTML内容。在传输数据时,您会推荐使用哪种协议?我正在考虑用字母填充每个值。例如:“Aint1A Bint2B Cint3C Dfloat1D ...”等等。您能否推荐一些后续教程/网页,以建议最佳方式打包和处理通过套接字到达C++程序的数据?
我提前为“修复我的代码”问题道歉,但我读过的所有问题都有点太高级了,因为它们涉及缓冲区溢出、安全性、端点问题、错误处理、畸形消息等等,这远远超出了我的需求(能力可能更准确)。非常感谢您的时间和帮助。
recv()
不能保证一次性返回所有数据,您需要在循环中调用它。 - Jonathan Potterrecv()
,所以你最多接收1到20000个字节,这些字节可能或可能不会(很可能不会)一次性包含完整的响应。你需要在循环中调用recv()
,直到你达到实际响应的结尾。这对于HTTP来说并不简单,因为HTTP是一种具有消息结构的协议,而你根本没有遵循这种结构,甚至没有接近。你必须使用类似于这个伪代码的逻辑。 - Remy Lebeau