I'm horribly new to c++ and programming in general. I'm simply trying to read a picture using opencv and display it on web server using boost asio. This is an initial step before I do this for all frames from a video. The following is my code -
#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <thread>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
using boost::asio::ip::tcp;
using namespace std;
using namespace cv;
int main(){
try{
boost::asio::io_service io_service;
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 1112));
for (;;){
tcp::socket socket(io_service);
acceptor.accept(socket);
boost::system::error_code ignored_error;
cv::Mat frame = cv::imread("x.jpg");
vector<uchar> buff;
vector<int> param = vector<int>(2);
param[0]=cv::IMWRITE_JPEG_QUALITY;
param[1]=95;
imencode(".jpg",frame,buff,param);
const char mess[] = "axaxaxaxasaaaaaaaaaaxax";
std::string content(buff.begin(), buff.end());
boost::asio::write(socket, boost::asio::buffer(content), boost::asio::transfer_all(), ignored_error);
// boost::asio::write(socket, boost::asio::buffer(mess), boost::asio::transfer_all(), ignored_error);
}
}
catch(std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
now sending the message works just fine but when i try to send the image via content or buff, it shows up as gibberish. I feel like it's because I'm not sending any information about the picture prior to sending the picture. But I can't figure out how to do that.
Or maybe I'm entirely wrong. Any help/advice would be appreciated. Cheers!
I've simplified the code a little:
#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <opencv2/opencv.hpp>
using boost::asio::ip::tcp;
int main(){
try{
boost::asio::io_service io_service;
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 1112));
for (;;){
tcp::socket socket(io_service);
acceptor.accept(socket);
cv::Mat frame = cv::imread("x.jpg");
std::vector<uchar> buff;
imencode(".jpg", frame, buff, std::vector<int> { cv::IMWRITE_JPEG_QUALITY, 95 });
boost::system::error_code err;
auto bytes_transferred = boost::asio::write(socket, boost::asio::buffer(buff), boost::asio::transfer_all(), err);
std::cout << "Written: " << bytes_transferred << " (" << err.message() << ")\n";
}
}
catch(std::exception& e)
{
std::cerr << e.what() << std::endl;
}
}
(specifically, don't use using namespace unneccessarily, not copying into a std::string unneccessarily, and not ignoring the error code unnecessarily)
Compiled it with
g++ test.cpp -L/usr/local/lib -pedantic -Wall -Wextra -pthread -lope^Cv_{core,imgproc,imgcodecs} -lboost_{system,thread} -o test.exe
Copied a sampe jpeg as x.jpg, running it in a terminal:
./test.exe
Then using netcat to read the result:
netcat localhost 1112 > verify.jpg
The server process will print the same message each time:
Written: 6130 (Success)
(6130 bytes happens to be the 95% re-encoded size of the test image I chose). The resulting image (verify.jpg) looks fine in my image viewer.
Conclusion
I think the code is probably fine (but check with the improvements above) and you might have been testing the result incorrectly.
Related
I know this is probably a really simple problem but ive been trying to get the asio examples to work correctly for over a week now. whenever I run the program, the terminal hangs and dosent print anything and dosent send any info to the client. Im using Ubuntu Linux and a basic compiler command
g++ main.cpp -o main.exe -I include
#define ASIO_STANDALONE;
#include <ctime>
#include <iostream>
#include <string>
#include <asio.hpp>
using asio::ip::tcp;
int main()
{
try
{
asio::io_context io_context;
tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), 1326));
for (;;)
{
std::cout << "hi";
tcp::socket socket(io_context);
acceptor.accept(socket);
std::string message = "e";
asio::error_code ignored_error;
asio::write(socket, asio::buffer(message), ignored_error);
break;
}
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
any help would be much appreciated
the terminal hangs and dosent print anything and dosent send any info to the client
You need to connect a client first, because the first thing you do is a blocking accept which never completes unless a connection arrives.
I've compiled your program (with minor modification for Boost Asio):
Live On Coliru
//#define ASIO_STANDALONE
#include <boost/asio.hpp>
#include <ctime>
#include <iostream>
#include <string>
namespace asio = boost::asio;
using asio::ip::tcp;
using boost::system::error_code;
int main() {
try {
asio::io_context io_context;
tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), 1326));
for (;;) {
tcp::socket socket(io_context);
acceptor.accept(socket);
std::cout << "hi " << socket.remote_endpoint() << std::endl;
std::string message = "server message works\n";
error_code ignored_error;
asio::write(socket, asio::buffer(message), ignored_error);
break;
}
} catch (std::exception const& e) {
std::cerr << e.what() << std::endl;
}
}
Using netcat to emulate a client:
nc 127.0.0.1 1326 -w 1 <<< "Hello world"
We see:
hi 127.0.0.1:45448
server message works
Or more clearly in separate terminals:
I was going through the boost asio tutorial trying to learn how to use their networking library. I implemented the example daytime client/server which is here (this is only the server). When running both the client and server I get can't allocate region of size mach_vm_map(size=7597121102135848960).
I have no idea why this is happening.
server:
#include <ctime>
#include <iostream>
#include <string>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
std::string make_daytime_string() {
using namespace std;
time_t now = time(NULL);
return ctime(&now);
}
int main() {
try {
boost::asio::io_service io;
tcp::acceptor acceptor(io);
tcp::endpoint endpoint(tcp::v4(), 13);
acceptor.open(endpoint.protocol());
acceptor.set_option(tcp::acceptor::reuse_address(true));
acceptor.bind(endpoint); // throwing error here
acceptor.listen();
for(;;) {
tcp::socket socket(io);
acceptor.accept(socket);
std::string message = make_daytime_string();
boost::system::error_code ignore_error;
boost::asio::write(socket, boost::asio::buffer(message), ignore_error);
}
}
catch(std::exception& e) {
std::cerr << e.what() << std::endl;
}
return 0;
}
client:
#include <iostream>
#include <boost/array.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
int main(int argc, char ** argv) {
try {
if(argc != 2) {
std::cerr << "Usage: client <host>" << std::endl;
return 1;
}
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
tcp::resolver::query query(argv[1], "daytime");
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::socket socket(io_service);
boost::asio::connect(socket, endpoint_iterator); // error here
for(;;) {
boost::array<char, 128> buf;
boost::system::error_code error;
size_t len = socket.read_some(boost::asio::buffer(buf), error);
if(error == boost::asio::error::eof)
break;
else if(error)
throw boost::system::system_error(error);
std::cout.write(buf.data(), len);
}
}
catch(std::exception& e) {
std::cerr << e.what() << std::endl;
}
return 0;
}
The error is basically the same for both with only a different size:
error:
sserver(14988,0x7fffdc3283c0) malloc: *** mach_vm_map(size=7597121102135848960) failed (error code=3)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
sserver(14988,0x7fffdc3283c0) malloc:
*** error for object 0x7373696d72655022: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
[1] 14988 abort ./sserver
I anyone know how to fix this I would greatly appreciate it. I should note that I am compiling with g++ 6.1.0 and boost 1.60.02.
How can I connect to my domain through my server, so that I can "host" it?
I've tried changing the code snippet below to match the IP with my domain's name, but a exception is caught saying that a invalid argument was supplied, I assumed I should resolve the domain name, get the IP and use the IP I got and not the one in the code snippet below, but it seems like I'm connecting to my external IP, and this doesn't let me host the server, as it says the machine actively refused the connection.
That's the code snippet:
boost::asio::ip::tcp::acceptor acceptor(service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string("192.168.1.3"), 8001));
That's the full code:
Main.cpp
#include "Server.h"
#include <string>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>
int main()
{
Server server;
boost::thread([&server] {
server.handleConnections();
}).join();
return 0;
}
Server.h
#ifndef SERVER_H
#define SERVER_H
#include <string>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>
class Server
{
private:
boost::asio::io_service service;
boost::asio::ip::tcp::socket sock;
protected:
public:
Server() : service(), sock(service) {
}
~Server() {
}
void handleConnections();
};
#endif
Server.cpp
#include "Server.h"
void Server::handleConnections() {
boost::system::error_code err;
try {
boost::asio::ip::tcp::acceptor acceptor(service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string("192.168.1.3"), 8001));
std::cout << acceptor.local_endpoint(err) << std::endl;
while (true) {
sock = boost::asio::ip::tcp::socket(service);
boost::system::error_code errCode;
acceptor.accept(this->sock, acceptor.local_endpoint(), errCode);
boost::asio::write(sock, boost::asio::buffer("Olá"), errCode);
}
this->sock.close();
}
catch (std::exception & e)
{
std::cout << e.what();
}
}
Firstly
acceptor.accept(this->sock, acceptor.local_endpoint(), errCode);
The documentation says:
This function is used to accept a new connection from a peer into the given socket, and additionally provide the endpoint of the remote peer. The function call will block until a new connection has been accepted successfully or an error occurs.
You ... pass the acceptor's local endpoint as the endpoint to receive the peer's remote endpoint (I'm surprised if that compiles). That makes little sense. I suggest you don't need to know the remote endpoint¹:
acceptor.accept(this->sock, errCode);
Secondly, you've bound to the loopback adaptor:
boost::asio::ip::tcp::acceptor acceptor(service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string("192.168.1.3"), 8001));
This directly implies you cannot access it from the network². Change it to be NIC-agnostic:
tcp::acceptor acceptor(service, tcp::endpoint(ip::address(), 8001));
¹ you can usually get it from the socket later using socket_->remote_endpoint() unless the socket has become invalid (e.g. closed)
² unless you implement some funky routing/tunneling logic, which is far stretch
UPDATE
Self contained demo with error handling:
Live On Coliru
#include <iostream>
#include <boost/asio.hpp>
class Server
{
boost::asio::io_service service;
public:
void handleConnections()
{
using namespace boost::asio;
boost::system::error_code err;
try {
ip::tcp::acceptor acceptor(service, ip::tcp::endpoint(ip::address(), 6768));
std::cout << acceptor.local_endpoint(err) << std::endl;
while (!err) {
ip::tcp::socket sock(service);
if ( !acceptor.accept(sock, err)
&& !write(sock, buffer("Olá"), err)
&& !sock.close(err))
{
std::cout << "Error in connection: " << err << " " << err.message() << "\n";
}
}
} catch (std::exception & e) {
std::cout << e.what();
}
}
};
#include <boost/thread.hpp>
int main() {
Server server;
boost::thread([&server] { server.handleConnections(); }).join();
}
Output:
$ ./a.out&
0.0.0.0:6768
$ while sleep 1; do nc 127.0.0.1 6768; done
OláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOláOlá
Above is my code which im using calling from my browser and other client. But it doesnt seem to work. Is there anything wrong? I want to know on which ip im running my server and how this can be used to create a restful webservice.
#include <ctime>
#include <iostream>
#include <string>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
using namespace std;
std::string make_daytime_string() {
using namespace std; // For time_t, time and ctime;
time_t now = time(0);
return ctime(&now);
}
int main() {
try {
boost::asio::io_service io_service;
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 13));
for (;;) {
cout << "listening for socket" << endl;
tcp::socket socket(io_service);
acceptor.accept(socket);
cout << "listening for socket" << endl;
std::string message = make_daytime_string();
boost::system::error_code ignored_error;
boost::asio::write(socket, boost::asio::buffer(message), ignored_error);
}
} catch (std::exception &e) {
std::cerr << e.what() << std::endl;
}
}
I'd guess that you are not running the program with sufficient permission to open the privileged (<1024) port 13.
Trying with 1313 works for me (without administrative privileges)
I want to use boost asio sockets to send a message from the server to the client and then print it out to the client terminal. I am trying to send the message "hello". It doesn't work. How can i fix this?
Thanks!
client:
#include <boost/asio.hpp>
#include <iostream>
#include <string>
using namespace std;
int main (int argc, char* argv[]) {
try {
boost::asio::io_service io_service;
boost::asio::ip::tcp::resolver::query query("localhost", "41005");
boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::resolver::iterator destination = resolver.resolve(query);
boost::asio::ip::tcp::resolver::iterator end ;
boost::asio::ip::tcp::endpoint endpoint;
while ( destination != end ) {
endpoint = *destination++;
std::cout<<endpoint<<std::endl;
}
boost::asio::ip::tcp::socket socket(io_service);
socket.connect(endpoint);
boost::array< char, 128 > buf;
boost::system::error_code error;
std::size_t length = boost::asio::read(socket, boost::asio::buffer(buf, 512), boost::asio::transfer_all(), error);
cout << length;
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
server:
#include <boost/asio.hpp>
#include <iostream>
#include <string>
using namespace std;
int main () {
try {
boost::asio::io_service io_service;
boost::asio::ip::tcp::acceptor acceptor(io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 41005));
for (; ;) {
std::cout<<"Listening to"<<std::endl;
boost::asio::ip::tcp::socket socket(io_service);
acceptor.accept(socket);
std::string message = "hello";
boost::system::error_code ignored_error;
boost::asio::write(socket, boost::asio::buffer(message), boost::asio::transfer_all(), ignored_error);
}
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
classic error: the "acceptor.accept" method is a blocking call, so the hello part is never called.
Our COut friend would help you, as allways:
...
std::cout<<"Sending hello"<