I'm having troubles setting the no_delay option on an asio socket. The following code runs well, except for the delay. My server receives the messages only after the 5000 ms expire.
#include <boost/asio.hpp>
#include <boost/thread.hpp>
using namespace boost::asio;
struct Client
{
io_service svc;
ip::tcp::socket sock;
Client() : svc(), sock(svc)
{
ip::tcp::resolver resolver(svc);
ip::tcp::resolver::iterator endpoint = resolver.resolve(boost::asio::ip::tcp::resolver::query("127.0.0.1", "32323"));
connect(sock, endpoint);
}
void send(std::string const& message) {
sock.send(buffer(message));
}
};
int main()
{
Client client;
client.send("hello world\n");
client.send("bye world\n");
boost::this_thread::sleep_for(boost::chrono::milliseconds(5000));
}
When trying to add a delay I have a few options:
1) Add the option before connection:
Client() : svc(), sock(svc)
{
ip::tcp::resolver resolver(svc);
ip::tcp::resolver::iterator endpoint = resolver.resolve(boost::asio::ip::tcp::resolver::query("127.0.0.1", "32323"));
sock.set_option(ip::tcp::no_delay(true));
connect(sock, endpoint);
}
However this throws set_option: Bad file descriptor
2) Add the option after the connection:
Client() : svc(), sock(svc)
{
ip::tcp::resolver resolver(svc);
ip::tcp::resolver::iterator endpoint = resolver.resolve(boost::asio::ip::tcp::resolver::query("127.0.0.1", "32323"));
connect(sock, endpoint);
sock.set_option(ip::tcp::no_delay(true));
}
However in this case, the option has no effect and I still see the delay. According to boost::asio with no_delay not possible? , I need to set the option after I've opened the socket but before I've connected the socket. So I've tried this:
Client() : svc(), sock(svc)
{
ip::tcp::endpoint endpoint( ip::address::from_string("127.0.0.1"), 32323);
sock.open(ip::tcp::v4());
sock.set_option(ip::tcp::no_delay(true));
sock.connect(endpoint);
}
However, I still see no effect. How can I set this option?
Edit: It's possible that I am not setting the option correctly on the server-side. This is the complete server code:
#include <boost/asio.hpp>
#include <iostream>
int main() {
boost::asio::io_service io_service;
boost::asio::ip::tcp::acceptor acceptor(io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 32323));
boost::asio::ip::tcp::socket socket(io_service);
acceptor.accept(socket);
socket.set_option(boost::asio::ip::tcp::no_delay(true));
boost::asio::streambuf sb;
boost::system::error_code ec;
while (boost::asio::read(socket, sb, ec)) {
std::cout << "received:\n" << &sb;
}
}
The client is properly setting the ip::tcp::no_delay option. However, the delay being observed is not the result of this option. Instead, it is the result of the server attempting to read more data than the client has sent, and when the client exits after sleeping 5000ms, the server's read operation completes with an error.
The read() operation initiated by the server will complete when either it has read streambuf.max_size() bytes or an error occurs. The streambuf's max size defaults to std::numeric_limits<std::size_t>::max() and can be configured in its constructor. In this case, the server attempts to read std::numeric_limits<std::size_t>::max() bytes, but the client only sends 22 bytes, sleeps 5000ms, then closes the socket. When the server observes that connection has closed, the read() operation completes with 22 bytes read and an error code of boost::asio::error::eof.
Related
When a client ab ends the reactor seems to indefinitely go into a polling state resulting in roughly 15% of the processor being used. If the client reconnects I'm still losing that 15%, I'm trying to determine what is lacking in my code to handle this properly.
When the client ab ends _socket.available() immediately returns false so in the else block I'm attempting to do the right thing. Doing the same thing I do when a client terminates normally, 'delete this' eliminates the processor issue but the next time a client connects I get an allocation error, I'd like to understand why that is, what's the difference? Just putting a sleep in there solves everything but onSocketReadable continues to be called with _socket.available() == false, so it remains as a sort of orphaned active reactor, what am I missing? I also tried stopping the reactor, that stops the processor use but the restarted client will no longer connect, there's something I don't understand there also, seems like a new reactor would be created just as it was initially?
void onSocketReadable(const AutoPtr<ReadableNotification>& pNf)
{
// some socket implementations (windows) report available
// bytes on client disconnect, so we double-check here
if (_socket.available())
{
// No FIFO for now
//int len = _socket.receiveBytes(_fifoIn);
char* buffer = new char[65535];
memset(buffer, 0, 65535);
_socket.setReceiveBufferSize(65535);
int n = _socket.receiveBytes(buffer, 65535);
std::string json = buffer;
delete [] buffer;
if (json == "SHUTDOWN\r\n")
{
delete this;
return;
}
try
{
std::string result = _processor.process(json,_sm);
result.append("\r\n");
_socket.sendBytes(result.data(), (int)result.length());
}
catch (Poco::Exception& e)
{
std::cout << e.message();
}
}
else
{
// delete this;
// return;
// _reactor.stop();
Sleep(10);
}
}
I made this Source code to implement lwip tcp server
If you try to remove the st-link wire and do it without debugging, the server itself doesn't work.
I try to find a way, but I don't know where the problem is.
If the LED on the board blinks, it means it's down.
Is there a problem with why the server is not working?
If you turn it to debugging, you receive it without any problems, generate a message, and then send it.
Then isn't there a problem with the Source code?
If the connection itself is not working when there is no debugging, I don't think the server is created
But if it's a circuit problem, I think it's weird to be a server when you debug it
I don't know where to look.
When debugging, the client sent and received properly when it connected to the client from hercules or Raspberry Pi
void Tcp_Task(void const * argument)
{
/* USER CODE BEGIN Tcp_Task */
struct netconn *conn, *newconn;
err_t err, accept_err;
struct netbuf *buf;
void *data;
u16_t len;
MX_LWIP_Init();
LWIP_UNUSED_ARG(argument);
conn = netconn_new(NETCONN_TCP);
if (conn!=NULL)
{
// netconn_bind(conn, NULL, port 번호)
err = netconn_bind(conn, NULL, 5001);
if (err == ERR_OK)
{
netconn_listen(conn);
while (1)
{
accept_err = netconn_accept(conn, &newconn);
if (accept_err == ERR_OK)
{
while (netconn_recv(newconn, &buf) == ERR_OK)
{
do
{
netbuf_data(buf, &data, &len);
memcpy(receivemsg, data, len);
transmitmsg = procPacket();
msg_len = getsendPackSize();
netconn_write(newconn, transmitmsg, msg_len, NETCONN_COPY);
}
while (netbuf_next(buf) >= 0);
netbuf_delete(buf);
}
netconn_close(newconn);
netconn_delete(newconn);
}
osDelay(100);
}
}
else
{
netconn_delete(newconn);
}
}
/* Infinite loop */
for(;;)
{
osDelay(100);
}
/* USER CODE END Tcp_Task */
}
lwip tcp server Source code site
[https://blog.naver.com/eziya76/221867311729](lwip tcp server)
I don't think I can implement the server if I turn the board off and on or without debugging, but I don't know where to find the problem
Please let me know if the Source code is the problem, and if the other place is the problem, please tell me how to find it
I'm writing this using a translator, so please understand
I'm working on an ESP-01 (ESP8266 board) project and making some HTTP requests. I'm trying to refactor my code to keep it DRY, but I'm stuck on how to extract the http client initialization to a function.
Here is my working PUT request function:
void httpPut(const char* url, const char* data) {
WiFiClient client;
HTTPClient http;
http.begin(client, url);
http.addHeader("Content-Type", "application/json");
http.PUT(data);
http.end();
}
My idea was to make a function like this:
HTTPClient prepareRequest(const char* url) {
WiFiClient client;
HTTPClient http;
http.begin(client, url);
http.addHeader("Content-Type", "application/json");
return http;
}
And use it in all my request functions like this:
void httpGet(const char* url) {
HTTPClient http = prepareRequest(url);
http.GET();
http.end();
}
I get this compiler error, but I'm not really sure what it means (row 90 mentioned is return http;):
/home/<user>/Code/Micro/mittari-micro/src/mittari.ino: In function 'HTTPClient prepareRequest(const char*)':
/home/<user>/Code/Micro/mittari-micro/src/mittari.ino:90:10: error: use of deleted function 'HTTPClient::HTTPClient(const HTTPClient&)'
90 | return http;
| ^~~~
In file included from /home/<user>/Code/Micro/mittari-micro/src/mittari.ino:2:
/home/<user>/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.h:151:7: note: 'HTTPClient::HTTPClient(const HTTPClient&)' is implicitly deleted because the default definition would be ill-formed:
151 | class HTTPClient
| ^~~~~~~~~~
/home/<user>/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.h:151:7: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = StreamString; _Dp = std::default_delete<StreamString>]'
In file included from /home/<user>/.platformio/packages/toolchain-xtensa/xtensa-lx106-elf/include/c++/10.3.0/memory:83,
from /home/<user>/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h:28,
from /home/<user>/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.h:28,
from /home/<user>/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266WiFi/src/ESP8266WiFi.h:34,
from /home/<user>/Code/Micro/mittari-micro/src/mittari.ino:1:
/home/<user>/.platformio/packages/toolchain-xtensa/xtensa-lx106-elf/include/c++/10.3.0/bits/unique_ptr.h:468:7: note: declared here
468 | unique_ptr(const unique_ptr&) = delete;
| ^~~~~~~~~~
Is it possible to extract the common functionality to a function and how could I do that?
You are trying to return a HTTPClient object (http) by value at the end of your prepareRequest function. This would mean copy construction in this case and the compiler is telling you that copy construction is deliberately disabled for this class. (There can be quite a number of reasons for this.)
How it is customary to do this in an Arduino environment is to move your "WiFiClient client" and "HTTPClient http" to global scope. Then write your initialization code into the "setup" function and finally you can use them in whatever functions you like. That way you can separate the setting of the URL and header into the "prepareRequest" function the actual http get into the "httpGet" function without them returning anything.
There are more complicated solutions with const references, pointers, etc... But unless you specifically want to go down that road, I would go for the solution mentioned above.
I put the WiFiClient and HTTPClient in global scope and changed the preparation method to void like this:
WiFiClient client;
HTTPClient http;
void prepareRequest(const char* url) {
http.end(); // In case previous request did not call end for some reason.
http.begin(client, url);
http.addHeader("Content-Type", "application/json");
}
void httpGet(const char* url) {
prepareRequest(url);
http.GET();
http.end();
}
It seems to work fine so far.
Trying to implement an asynchronous client based in mosquitto MQTT broker, running forever in the background. My purpose is create a client able to connect / reconnect to broker in case the broker becomes offline at some time. I expected all connection / reconnection logic was managed by mosquitto callbacks (event-driven). However, this code doesn't try to connect to broker in case you try to run the client when the broker is stopped (offline) at initial time:
struct mosquitto *broker;
char ip[INET_ADDRSTRLEN]; // broker ip address
int port; // 1883
int keepalive; // 60
bool running = true;
int main(void)
{
mosquitto_lib_init();
broker = mosquitto_new(NULL, true, NULL);
mosquitto_connect_callback_set(broker, on_connect_callback);
mosquitto_disconnect_callback_set(broker, on_disconnect_callback);
mosquitto_message_callback_set(broker, on_message_callback);
mosquitto_connect_async(broker, ip, port, keepalive);
mosquitto_loop_start(broker);
while(running) {
pause();
}
}
After some testing, replaced
mosquitto_connect_async(broker, ip, port, keepalive);
by a while loop polling for the first success returned by mosquitto_connect_async function:
bool connected_to_broker = false;
while (!connected_to_broker) {
rc = mosquitto_connect_async(broker, ip, port, keepalive);
if (rc == MOSQ_ERR_SUCCESS) {
connected_to_broker = true;
} else {
sleep(retry_timeout);
}
}
After the while loop, it seems all the source code can be based on mosquitto callbacks.
Is this the expected way to manage this situation? Or should be managed in a different way? Thanks!
You don't have to make multiple connection attempts. Your problem is that the first attempt fails for the same reason but does not yet fire any callbacks because the communication thread is not yet started.
If you check the return value of mosquitto_connect_async you will see it is MOSQ_ERR_ERRNO with errno being set to ECONNREFUSED (111).
If mosquitto_loop_start is called before your first connection attempt, the disconnect callback should be fired - also with rc == MOSQ_ERR_ERRNO and errno == ECONNREFUSED
I'm programming my ESP32 with the ArduinoIDE and have a problem with HTTP GET. What I'm doing:
the ESP32 connects as WiFi client to an existing WiFi network using a static, fixed IP
a webserver is started which provides a webpage for OTA firmware update -> this works, the webpage is accessible via the static IP
using HttpClient I try to GET an other, remote webserver, but this fails
This is the code I'm using for the HTTP GET call:
static WiFiClient wifi;
HttpClient wlanHttp=HttpClient(wifi,"my.server.tld");
wlanHttp.get("/setpos.php?id=DEADBEEF"); // -> this fails with error code -1
wlanHttp.responseStatusCode(); // follow-up error -1
wlanHttp.stop();
Any idea what goes wrong here?
The confusing part here is the ESP32 has a built in http client called HTTPClient. The one for Arduino is called HttpClient and I'd like to find the guy who decided on that name and see if he's okay. HTTPClient has a routine called getString() that is a lovely way to gather info from a json api call, but HttpClient won't compile with that because it has no clue what that is.
On ESp32 (if using the HTTPClient.h) the code should look like that:
static WiFiClient wifi;
HttpClient wlanHttp;
wlanHttp.begin("http://my.server.tld/setpos.php?id=DEADBEEF"); //Specify the URL
int httpCode = wlanHttp.GET(); //Make the request
if (httpCode > 0) { //Check for the returning code
if (httpCode == HTTP_CODE_OK) {
// get payload with http.getString();
Serial.println(httpCode);
// Serial.println(payload);
} else {
Serial.printf("[HTTP] GET... failed, error: %s\n", wlanHttp.errorToString(httpCode).c_str());
}
} else {
Serial.println("Error on HTTP request");
}
wlanHttp.end(); //Free the resources