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:
Related
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.
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 am following the Introduction to Sockets boost::asio tutorial here, called a A synchronous TCP daytime client. I have copied the code exactly, but then moved them into Server.cpp and Client.cpp.
Server.cpp
#include <ctime>
#include <iostream>
#include <string>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
std::string make_daytime_string()
{
std::time_t now = time(0);
return ctime(&now);
}
int main()
{
try {
std::cout << "Initiating server..." << std::endl;
boost::asio::io_service io;
tcp::acceptor acceptor (io, tcp::endpoint(tcp::v4(), 8889));
for (;;) {
tcp::socket socket (io);
acceptor.accept(socket);
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;
}
return 0;
}
Client.cpp
#include <boost/array.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
int main(int argc, char * argv[])
{
boost::asio::io_service io;
// Daytime
try {
if (argc != 2) {
std::cerr << "Usage: client <host>" << std::endl;
return 1;
}
tcp::resolver resolver (io);
tcp::resolver::query query (argv[1], "daytime");
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::socket socket (io);
boost::asio::connect(socket, endpoint_iterator);
for (;;) {
boost::array<char, 128> buffer;
boost::system::error_code error;
size_t len = socket.read_some(boost::asio::buffer(buffer), error);
if (error == boost::asio::error::eof) {
break; // Connection closed cleanly by peer.
}
else if (error) {
throw boost::system::system_error(error); // Some other error.
}
std::cout.write(buffer.data(), len);
}
}
catch (std::exception & e) {
std::cerr << e.what() << std::endl;
}
return 0;
}
First I run the server:
$ ./server
Initiating server...
Then I run the client:
$ ./client localhost
connect: Connection refused
Since I am brand new to sockets and boost, unfortunately I am stuck on finding a solution to this connection refused error message.
Your server is running on port 8889.
Your client connects on port 13 (a.k.a. "daytime").
This will not work. For the obvious reason.
Note if you do decide to run the server on port 13, you need administrative privileges for that.
Learning boost, and compiled their daytime server client example. Since I cant use port 13 that is in the example I only changed the port numbers in the server and client example. Server runs fine, but the client doesnt connect it seems, and no error is given.
Input data for the client is "127.0.0.1".
Server:
#include <ctime>
#include <iostream>
#include <string>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
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::endpoint endpoint(tcp::v4(), 8087);
tcp::acceptor acceptor(io_service, endpoint);
for (;;)
{
tcp::iostream stream;
acceptor.accept(*stream.rdbuf());
stream << "test" << make_daytime_string();
}
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
And the client:
#include <iostream>
#include <string>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
int main(int argc, char* argv[])
{
try
{
if (argc != 2)
{
std::cerr << "Usage: daytime_client <host>" << std::endl;
return 1;
}
tcp::iostream s(argv[1], 8087);
std::string line;
std::getline(s, line);
std::cout << line << std::endl;
}
catch (std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
}
return 0;
}
What worked for me was to change the way I create the endpoint from
tcp::endpoint( tcp::v4(), port );
to
tcp::endpoint( boost::asio::ip::address::from_string("127.0.0.1"), port );
The first method creates an endpoint of 0.0.0.0 which works fine on Mac OS X, but gives the "not valid" message on Windows (XP, building with MSVC 2008).
I wouldn't mind knowing WHY the difference, but at least it works.
A few things would help to debug this for you:
What platform are you running
What compiler are your using, including version
What version of boost are you using
Also, one thing to check is whether the server is binding to 127.0.0.1 or the external interface. Try using the IP address of your external interface instead of 127.0.0.1. Check this in windows using ipconfig and in linux using ifconfig.
Hmm, all works on 1_36 boost version and msvc 2005 compiller.
Check your firewall settings.
The port option takes a string, which may be the name of the service, as "daytime", and then it will look up the corresponding port, or explicitly the port, but it must be a string:
tcp::iostream s(argv[1], "8087");