I'm running the following code in order to create listener to unix domain socket.
Under macOS this code is working fine, but in Windows it produces the following error from the tcp_acceptor command : WSAEOPNOTSUPP
Here's a minimal reproducible example :
#include <iostream>
#include <boost/asio/local/stream_protocol.hpp>
constexpr char* kFileName = "file.sock";
using namespace std;
using namespace boost::asio;
int main(int argc, char* argv[])
{
io_context my_io_context;
::_unlink(kFileName); // Remove previous binding.
local::stream_protocol::endpoint server(kFileName);
local::stream_protocol::acceptor acceptor(my_io_context, server);
local::stream_protocol::socket socket(my_io_context);
acceptor.accept(socket);
return 0;
}
While debugging inside the boost library, i saw that the failure comes from the internal bind in the following code :
and this is the frame variables (it's clearly visible that sa_family = AF_UNIX (1):
I know that unix domain socket was introduced in windows10 few years ago, and i'm working with the latest version so it should be supported. Any idea what's wrong in my code?
EDIT : I've found out that in linux based machine I pass the following sockaddr to ::bind
(const boost::asio::detail::socket_addr_type) *addr = (sa_len = '\0', sa_family = '\x01', sa_data = "/tmp/server.sock")
(lldb) memory read addr
0x7ffeefbffa00: 00 01 2f 74 6d 70 2f 73 65 72 76 65 72 2e 73 6f ../tmp/server.so
0x7ffeefbffa10: 63 6b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ck..............```
and in windows i get a slightly different struct :
{sa_family=1 sa_data=0x000000fffd33f682 "C:\\temp\\UnixSo... }const sockaddr *
Notice that the len field is missing in the windows platform.
Thanks
The issue seems to be the SO_REUSEADDR socket option, which ASIO by default sets. Setting this option itself succeeds, but causes the subsequent bind to fail.
Construct the acceptor with reuse_addr = false, then the binding should succeed:
local::stream_protocol::acceptor acceptor(my_io_context, server, false);
I want to print the UID of a card as an HID with the Arduino Leonardo.
Here is the code that I have
void loop() {
if ( mfrc522.PICC_IsNewCardPresent()) {
// Select one of the cards
if ( mfrc522.PICC_ReadCardSerial()) {
// Dump debug info about the card; PICC_HaltA() is automatically called
mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
Keyboard.print(mfrc522.uid);
}
}
}
and this is what the compiler says
note: no known conversion for argument 1 from 'MFRC522::Uid' to 'const Printable&'
exit status 1
Does anyone know how to do it?
I believe that the isse you are facing is that you are trying to print a MFRC522::Uid which is a HEX number such as 00 00 00 00 while the keyboard.print() only accepts char, int or string according to: Arduino.cc. I found the following code snippet here. I believe it might resolve your issue. It should write: "Card UID: 00 00 00 00".
Serial.print("Card UID:"); //Dump UID
for (byte i = 0; i < mfrc522.uid.size; i++) {
Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
Serial.print(mfrc522.uid.uidByte[i], HEX);
}
NOTE: If you are using Keyboard.print() I believe you need to use Keyboard.begin() in your setup method.
OK. So this memory leak occurs randomly. And I tried to reproduce it in a simplified version of my original program. It's a VC++ console application with common header files for MFC.
The following is my memManager class, which originally is a image correction class that manages memory and also processes image.
typedef struct Point
{
int x;
int y;
}TPoint;
class memManager
{
public:
memManager();
~memManager();
void AllocMemory(TPoint **pAddr, int nSize);
void ReleaseMemory(TPoint **pAddr);
void ReleaseAllMemory();
TPoint* ptsPtr;
};
memManager::memManager()
{
ptsPtr = NULL;
}
memManager::~memManager()
{
ReleaseAllMemory();
}
void memManager::AllocMemory(TPoint **pAddr, int nSize)
{
if (*pAddr != NULL)
return;
TPoint *pTempAddr;
pTempAddr = new TPoint[nSize];
memset(pTempAddr, 0, sizeof(TPoint)*nSize);
*pAddr = pTempAddr;
return;
}
void memManager::ReleaseMemory(TPoint **pAddr)
{
if (*pAddr != NULL)
{
delete[] * pAddr;
*pAddr = NULL;
}
return;
}
void memManager::ReleaseAllMemory()
{
ReleaseMemory(&ptsPtr);
return;
}
And here is the the code in the main function.
memManager myMemManager;
myMemManager.AllocMemory(&myMemManager.ptsPtr,5000000);
system("pause");
When I debug the program, the console window shows with a prompt "Press any key to continue." And then I close the window by clicking the close button. One out of ten times, the output window of visual studio shows the following:
Detected memory leaks!
Dumping objects ->
{83} normal block at 0x000001FC942D9070, 40000000 bytes long.
Data: < > 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Object dump complete."
The program '[348] testForMemLeak.exe' has exited with code -1073741510 (0xc000013a).
I found it tricky to reproduce the result. Only if I clicked the close button right after the "busy" blue circle disappeared, should I get the memory leak message.
Is it because my memory handling function isn't good enough, or because the console application refused to call the destructor of memManager when I close the console window with bad timing?
Thanks.
I am having a problem using a state machine setup. I am knew to these so I am having a problem. So there are some methods here can be ignored. The main problem is for some reason it sends a message for every byte it receives, but I thought Serial.read() clears the buffer after reading.
So here is the bulk of the code:
#include "Arduino_Structures.h"
#include <SPI.h>
#include <Ethernet.h>
#include "Time.h"
//GLOBAL DECLARATIONS
enum { STANDBY, SEND, RECEIVE, PROCESS} state = SEND;
enum { STATUS, CONFIG, CURRENT, TIME, VOLTAGE} messageType = STATUS;
char lcv;
char lcv2; //loop control variables
MESSAGE_STRUCT outgoing; //changing outgoing message
MESSAGE_STRUCT incoming; //changing incoming message
OODLES_BLOCK oodles; //oodles of information from the following 5 blocks
STATUS_BLOCK temp_status; //temporary status block
CONFIG_BLOCK temp_config; //temporary config block
CURRENT_BLOCK temp_current; //temporary current block
TIME_BLOCK temp_time; //temporary time block
VOLTAGE_BLOCK temp_voltage; //temporary voltage block
//FUNCATION DECLARATIONS
void sendMsg(MESSAGE_STRUCT* outgoing);
void receiveMsg(MESSAGE_STRUCT* incoming);
//ARDUINO SETUP
void setup()
{
delay(TIMEOUT); //wait for the boards to start up
Serial.begin(BAUD); //set the arduino to be at the Micro-AT baud rate
do
{
lcv = Ethernet.begin(mac); //start etherent board, get IP
}while(!lcv);
}
//ARDUINO LOOP
void loop()
{
switch(state)
{
case STANDBY:
delay(1000);
state = SEND;
break;
case SEND:
switch(messageType)
{
case STATUS:
outgoing.start_byte = 0x00;
outgoing.length = 0x00;
outgoing.address_1 = 0xFF;
outgoing.address_2 = 0xFF;
outgoing.code_word = REQUEST_STATUS;
outgoing.checksum = 0;
sendMsg(&outgoing);
state = RECEIVE;
break;
case CONFIG:
outgoing.start_byte = 0x00;
outgoing.length = 0x00;
outgoing.address_1 = 0xFF;
outgoing.address_2 = 0xFF;
outgoing.code_word = REQUEST_CONFIG;
outgoing.checksum = 0;
sendMsg(&outgoing);
state = RECEIVE;
break;
case CURRENT:
outgoing.start_byte = 0x00;
outgoing.length = 0x00;
outgoing.address_1 = 0xFF;
outgoing.address_2 = 0xFF;
outgoing.code_word = REQUEST_CURRENT;
outgoing.checksum = 0;
sendMsg(&outgoing);
state = RECEIVE;
break;
case TIME:
outgoing.start_byte = 0x00;
outgoing.length = 0x00;
outgoing.address_1 = 0xFF;
outgoing.address_2 = 0xFF;
outgoing.code_word = REQUEST_TIME;
outgoing.checksum = 0;
sendMsg(&outgoing);
state = RECEIVE;
break;
case VOLTAGE:
outgoing.start_byte = 0x00;
outgoing.length = 0x00;
outgoing.address_1 = 0xFF;
outgoing.address_2 = 0xFF;
outgoing.code_word = REQUEST_VOLTAGE;
outgoing.checksum = 0;
sendMsg(&outgoing);
state = RECEIVE;
break;
default:
break;
}
break;
case RECEIVE:
if(Serial.available())
{
state = SEND;
receiveMsg(&incoming);
//NEED TO CHECK TO MAKE SURRE START BYTE AND ADDRESS ARE CORRECT
//ALSO THIS IS WHERE I SHOULD CHECK THE CHECKSUM
//ONCE INSIDE SWITCHES NEED TO MAKE SURE THE RESPONSE IS CORRECT
switch(messageType)
{
case STATUS:
//copy information from incoming's data array to the temp_status block so that it retains its structure
memcpy(&temp_status, &incoming.data, sizeof(STATUS_BLOCK));
//these are directly taken from the status block information (Arduino_Structures.h)
oodles.left_source = temp_status.left_source;
oodles.right_source = temp_status.right_source;
oodles.left_overcurrent = temp_status.left_overcurrent;
oodles.right_overcurrent = temp_status.right_overcurrent;
oodles.automatic_transfer = temp_status.ready;
oodles.event_led = temp_status.event;
oodles.bus_type = temp_status.bus_type;
oodles.preferred = temp_status.preferred;
oodles.lockout_installed = temp_status.lockout_installed;
oodles.supervisory_control = temp_status.supervisory_control;
//put the time into the TimeElement then convert it to unix time
TimeElements timeInfo; //will be used (from Time.h library)
timeInfo.Year = temp_status.year;
timeInfo.Month = temp_status.month;
timeInfo.Day = temp_status.day;
timeInfo.Hour = temp_status.hour;
timeInfo.Minute = temp_status.minute;
timeInfo.Second = temp_status.second;
oodles.unix_time = makeTime(timeInfo);
//might want to wipe incoming and outogoing messages to make sure they get correctly rewritten
//messageType = CONFIG;
//state = SEND;
break;
case CONFIG:
break;
case CURRENT:
break;
case TIME:
break;
case VOLTAGE:
break;
}
}
break;
case PROCESS:
break;
}
}
void sendMsg(MESSAGE_STRUCT* message)
{
//brake up integers from MESSAGE_STRUCT to bytes (see intByte in Arduino_Structures.h)
intByte code_word, checksum;
code_word.intValue = message->code_word;
checksum.intValue = message->checksum;
//send byte by byte
Serial.write(message->start_byte);
Serial.write(message->length);
Serial.write(message->address_1);
Serial.write(message->address_2);
Serial.write(code_word.byte1);
Serial.write(code_word.byte2);
for(lcv = 0; lcv < message->length; lcv++)
Serial.write(message->data[lcv]);
Serial.write(checksum.byte1);
Serial.write(checksum.byte2);
}
void receiveMsg(MESSAGE_STRUCT* message)
{
//receive bytes and put them back as integers (see intByte in Arduino_Structures.h)
intByte code_word, checksum;
//receive byte by byte
message->start_byte = Serial.read();
message->length = Serial.read();
message->address_1 = Serial.read();
message->address_2 = Serial.read();
code_word.byte1 = Serial.read();
code_word.byte2 = Serial.read();
message->code_word = code_word.intValue;
for(lcv = 0; lcv < message->length; lcv++)
message->data[lcv] = Serial.read();
checksum.byte1 = Serial.read();
checksum.byte2 = Serial.read();
message->checksum = checksum.intValue;
}
And here is the Serial monitor showing the error, it should only respond once, and if I send it only one byte it responds once. If I send it an 8 byte response as below, it responds 8 times("Answer" means arduino to laptop, and "request" means laptop to arduino):
Answer: 6/26/2013 4:30:59 PM.56364 (+11.3133 seconds)
00 00 FF FF 00 01 00 00
Request: 6/26/2013 4:31:00 PM.48564 (+0.9219 seconds)
00 00 FF FF 01 01 00 00
Answer: 6/26/2013 4:31:00 PM.51664 (+0.0156 seconds)
00 00 FF FF 00 01 00 00 00 00 FF FF 00 01 00 00
00 00 FF FF 00 01 00 00 00 00 FF FF 00 01 00 00
00 00 FF FF 00 01 00 00 00 00 FF FF 00 01 00 00
00 00 FF FF 00 01 00 00 00 00 FF FF 00 01 00 00
It looks like you're checking to see that Serial.available() is not zero and then reading a bunch of data. It could be that you are not done recieving the data when you begin your receiveMsg function. You should:
Check to make sure that the bytes you need are available Wait if
They are not available, but you expect them to be coming soon
Just as an example:
void receiveMsg(MESSAGE_STRUCT* message)
{
// receive bytes and put them back as integers
intByte code_word, checksum;
// receive byte by byte, wait for it if need be
while( Serial.available() < 1 ) {delay(10);}
message->start_byte = Serial.read();
while( Serial.available() < 1 ) {delay(10);}
message->length = Serial.read();
There are better, more robust ways to do it, but this is pretty simple and easily implemented for a test to see if the input buffer is not getting filled.
So working off of the boost HTTP Server 3 example, I want to modify connection::handle_read to support sending a body along with the message. However, the method for doing this is not apparent to me. I want to write something like:
void connection::handle_read(const boost::system::error_code& e,
std::size_t bytes_transferred)
{
...
if (result)
{
boost::asio::async_write(socket_, reply.to_buffers(),
strand_.wrap(
boost::bind(&connection::write_body, shared_from_this(),
boost::asio::placeholders::error)));
}
}
void connection::write_body(const boost::system::error_code& e)
{
boost::asio::async_write(socket_, body_stream_,
strand_.wrap(
boost::bind(&connection::handle_write, shared_from_this(),
boost::asio::placeholders::error)));
}
where body_stream_ is an asio::windows::stream_handle.
But this approach doesn't handle the http chunking at all (all that means is the size of the chunk is sent before each chunk). What is the best way to approach this problem? Do I write my own wrapper for an ifstream that adheres to the requiresments of a boost const buffer? Or try to simulate the effect of async_write with multiple calls to async_write_some in a loop? I should mention a requirement of the solution is that I never have the entire file in memory at any given time - only one or a few chunks.
Very new to ASIO and sockets, any advice is appreciated!
It may be easier to visualize asynchronous programming as a chain of functions rather than looping. When breaking apart the chains, I find it to be helpful to break operations into two parts (initiation and completion), then illustrate the potential call paths. Here is an example illustration that asynchronously reads some data from body_stream_, then writes it out the socket via HTTP Chunked Transfer Encoding:
void connection::start()
{
socket.async_receive_from(..., &handle_read); --.
} |
.----------------------------------------------'
| .-----------------------------------------.
V V |
void connection::handle_read(...) |
{ |
if (result) |
{ |
body_stream_.assign(open(...)) |
|
write_header(); --------------------------------|-----.
} | |
else if (!result) | |
boost::asio::async_write(..., &handle_write); --|--. |
else | | |
socket_.async_read_some(..., &handle_read); ----' | |
} | |
.---------------------------------------------------' |
| |
V |
void connection::handle_write() |
{} |
.------------------------------------------------------'
|
V
void connection::write_header()
{
// Start chunked transfer coding. Write http headers:
// HTTP/1.1. 200 OK\r\n
// Transfer-Encoding: chunked\r\n
// Content-Type: text/plain\r\n
// \r\n
boost::asio::async_write(socket_, ...,
&handle_write_header); --.
} .-------------------------'
|
V
void connection::handle_write_header(...)
{
if (error) return;
read_chunk(); --.
} .-------------'
| .--------------------------------------------.
V V |
void connection::read_chunk() |
{ |
boost::asio::async_read(body_stream_, ..., |
&handle_read_chunk); --. |
} .-----------------------' |
| |
V |
void connection::handle_read_chunk(...) |
{ |
bool eof = error == boost::asio::error::eof; |
|
// On non-eof error, return early. |
if (error && !eof) return; |
|
write_chunk(bytes_transferred, eof); --. |
} .-------------------------------------' |
| |
V |
void connection::write_chunk(...) |
{ |
// Construct chunk based on rfc2616 section 3.6.1 |
// If eof has been reached, then append last-chunk. |
boost::asio::async_write(socket_, ..., |
&handle_write_chunk); --. |
} .------------------------' |
| |
V |
void connection::handle_write_chunk(...) |
{ |
// If an error occured or no more data is available, |
// then return early. |
if (error || eof) return; |
|
// Read more data from body_stream_. |
read_chunk(); ---------------------------------------'
}
As illustrated above, the chunking is done via an asynchronous chain, where data is read from body_stream_, prepared for writing based on the HTTP Chunked Transfer Encoding specification, then written to the socket. If body_stream_ still has data, then another iteration occurs.
I do not have a Windows environment to test on, but here is a basic complete example on Linux that chunks data 10 bytes at a time.
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
using boost::asio::ip::tcp;
namespace posix = boost::asio::posix;
// Constant strings.
const std::string http_chunk_header =
"HTTP/1.1 200 OK\r\n"
"Transfer-Encoding: chunked\r\n"
"Content-Type: text/html\r\n"
"\r\n";
const char crlf[] = { '\r', '\n' };
const char last_chunk[] = { '0', '\r', '\n' };
std::string to_hex_string(std::size_t value)
{
std::ostringstream stream;
stream << std::hex << value;
return stream.str();
}
class chunk_connection
{
public:
chunk_connection(
boost::asio::io_service& io_service,
const std::string& pipe_name)
: socket_(io_service),
body_stream_(io_service),
pipe_name_(pipe_name)
{}
/// Get the socket associated with the connection
tcp::socket& socket() { return socket_; }
/// Start asynchronous http chunk coding.
void start(const boost::system::error_code& error)
{
// On error, return early.
if (error)
{
close();
return;
}
std::cout << "Opening pipe." << std::endl;
int pipe = open(pipe_name_.c_str(), O_RDONLY);
if (-1 == pipe)
{
std::cout << "Failed to open pipe." << std::endl;
close();
return;
}
// Assign native descriptor to Asio's stream_descriptor.
body_stream_.assign(pipe);
// Start writing the header.
write_header();
}
private:
// Write http header.
void write_header()
{
std::cout << "Writing http header." << std::endl;
// Start chunked transfer coding. Write http headers:
// HTTP/1.1. 200 OK\r\n
// Transfer-Encoding: chunked\r\n
// Content-Type: text/plain\r\n
// \r\n
boost::asio::async_write(socket_,
boost::asio::buffer(http_chunk_header),
boost::bind(&chunk_connection::handle_write_header, this,
boost::asio::placeholders::error));
}
/// Handle writing of http header.
void handle_write_header(const boost::system::error_code& error)
{
// On error, return early.
if (error)
{
close();
return;
}
read_chunk();
}
// Read a file chunk.
void read_chunk()
{
std::cout << "Reading from body_stream_...";
std::cout.flush();
// Read body_stream_ into chunk_data_ buffer.
boost::asio::async_read(body_stream_,
boost::asio::buffer(chunk_data_),
boost::bind(&chunk_connection::handle_read_chunk, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
// Handle reading a file chunk.
void handle_read_chunk(const boost::system::error_code& error,
std::size_t bytes_transferred)
{
bool eof = error == boost::asio::error::eof;
// On non-eof error, return early.
if (error && !eof)
{
close();
return;
}
std::cout << bytes_transferred << " bytes read." << std::endl;
write_chunk(bytes_transferred, eof);
}
// Prepare chunk and write to socket.
void write_chunk(std::size_t bytes_transferred, bool eof)
{
std::vector<boost::asio::const_buffer> buffers;
// If data was read, create a chunk-body.
if (bytes_transferred)
{
// Convert bytes transferred count to a hex string.
chunk_size_ = to_hex_string(bytes_transferred);
// Construct chunk based on rfc2616 section 3.6.1
buffers.push_back(boost::asio::buffer(chunk_size_));
buffers.push_back(boost::asio::buffer(crlf));
buffers.push_back(boost::asio::buffer(chunk_data_, bytes_transferred));
buffers.push_back(boost::asio::buffer(crlf));
}
// If eof, append last-chunk to outbound data.
if (eof)
{
buffers.push_back(boost::asio::buffer(last_chunk));
buffers.push_back(boost::asio::buffer(crlf));
}
std::cout << "Writing chunk..." << std::endl;
// Write to chunk to socket.
boost::asio::async_write(socket_, buffers,
boost::bind(&chunk_connection::handle_write_chunk, this,
boost::asio::placeholders::error,
eof));
}
// Handle writing a chunk.
void handle_write_chunk(const boost::system::error_code& error,
bool eof)
{
// If eof or error, then shutdown socket and return.
if (eof || error)
{
// Initiate graceful connection closure.
boost::system::error_code ignored_ec;
socket_.shutdown(tcp::socket::shutdown_both, ignored_ec);
close();
return;
}
// Otherwise, body_stream_ still has data.
read_chunk();
}
// Close the socket and body_stream.
void close()
{
boost::system::error_code ignored_ec;
socket_.close(ignored_ec);
body_stream_.close(ignored_ec);
}
private:
// Socket for the connection.
tcp::socket socket_;
// Stream file being chunked.
posix::stream_descriptor body_stream_;
// Buffer to read part of the file into.
boost::array<char, 10> chunk_data_;
// Buffer holds hex encoded value of chunk_data_'s valid size.
std::string chunk_size_;
// Name of pipe.
std::string pipe_name_;
};
int main()
{
boost::asio::io_service io_service;
// Listen to port 80.
tcp::acceptor acceptor_(io_service, tcp::endpoint(tcp::v4(), 80));
// Asynchronous accept connection.
chunk_connection connection(io_service, "example_pipe");
acceptor_.async_accept(connection.socket(),
boost::bind(&chunk_connection::start, &connection,
boost::asio::placeholders::error));
// Run the service.
io_service.run();
}
I have a small html file that will be served over chunked encoding, 10 bytes at a time:
<html>
<body>
Test transfering html over chunked encoding.
</body>
</html>
Running server:
$ mkfifo example_pipe
$ sudo ./a.out &
[1] 28963
<open browser and connected to port 80>
$ cat html > example_pipe
The output of the server:
Opening pipe.
Writing http header.
Reading from body_stream_...10 bytes read.
Writing chunk...
Reading from body_stream_...10 bytes read.
Writing chunk...
Reading from body_stream_...10 bytes read.
Writing chunk...
Reading from body_stream_...10 bytes read.
Writing chunk...
Reading from body_stream_...10 bytes read.
Writing chunk...
Reading from body_stream_...10 bytes read.
Writing chunk...
Reading from body_stream_...10 bytes read.
Writing chunk...
Reading from body_stream_...7 bytes read.
Writing chunk...
The wireshark output shows no-malformed data:
0000 48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d HTTP/1.1 200 OK.
0010 0a 54 72 61 6e 73 66 65 72 2d 45 6e 63 6f 64 69 .Transfe r-Encodi
0020 6e 67 3a 20 63 68 75 6e 6b 65 64 0d 0a 43 6f 6e ng: chun ked..Con
0030 74 65 6e 74 2d 54 79 70 65 3a 20 74 65 78 74 2f tent-Typ e: text/
0040 68 74 6d 6c 0d 0a 0d 0a 61 0d 0a 3c 68 74 6d 6c html.... a..<html
0050 3e 0a 3c 62 6f 0d 0a 61 0d 0a 64 79 3e 0a 20 20 >.<bo..a ..dy>.
0060 54 65 73 74 0d 0a 61 0d 0a 20 74 72 61 6e 73 66 Test..a. . transf
0070 65 72 69 0d 0a 61 0d 0a 6e 67 20 68 74 6d 6c 20 eri..a.. ng html
0080 6f 76 0d 0a 61 0d 0a 65 72 20 63 68 75 6e 6b 65 ov..a..e r chunke
0090 64 0d 0a 61 0d 0a 20 65 6e 63 6f 64 69 6e 67 2e d..a.. e ncoding.
00a0 0d 0a 61 0d 0a 0a 3c 2f 62 6f 64 79 3e 0a 3c 0d ..a...</ body>.<.
00b0 0a 37 0d 0a 2f 68 74 6d 6c 3e 0a 0d 0a 30 0d 0a .7../htm l>...0..
00c0 0d 0a ..
the example is very simple,just to show you how to hanlde HTTP request simply.Chunked Transfer Encoding is not support for this example.
some suggestion for you :
to learn what is the Chunked Transfer Encoding,you can found it in RFC2616,section 3.6.
do something before send:
set HTTP headers to indicate that the reapons message using Chunked Transfer Encoding;
encode your data with Chunked Transfer Encoding.
the logic will be like this:
std::string http_head;
std::string http_body;
char buff[10000];
read_file_to_buff(buff);
set_http_head_values(http_head);
encode_chunk_format(buff,http_body);
boost::asio::async_write(socket_,
boost::asio::buffer(http_head.c_str(), http_head.length()),
boost::bind(&connection::handle_write, shared_from_this(),
boost::asio::placeholders::error);
boost::asio::async_write(socket_,
boost::asio::buffer(http_body.c_str(), http_body.length()),
boost::bind(&connection::handle_write, shared_from_this(),
boost::asio::placeholders::error);
when you test your program,you can use Fiddler2 to monitor http message.
So the solution I came up is to have 2 write functions - write_body() and write_complete(). Once reading is done, assuming we have a body to send, we call
body_fp_.open(bodyFile);
async_write(get_headers(), write_body)
inside write_body, we do something like
vector<boost::asio::const_buffer> buffers;
body_fp_.read(buffer_, buffer_.size())
buffers.push_back(...size, newlines, etc...);
buffers.push_back(buffer_, body_fp_.gcount());
and once we finish writing the file contents, write a final time with:
boost::asio::async_write(socket_, boost::asio::buffer(misc_strings::eob),
strand_.wrap(
boost::bind(&connection::write_complete, shared_from_this(),
boost::asio::placeholders::error)));
This seems to work pretty well, and has alleviated concerns with memory usage. Any comments on this solution are appreciated; hopefully this will help someone else with a similar problem in the future.