c++ socket stream api - c++

I'm using what looks to be a real nice API for streaming sockets found here:
http://www.pcs.cnu.edu/~dgame/sockets/socketsC++/sockets.html.
I'm having trouble accessing the IP of the connected user because its a private member of a class "Socket" that is used within another class "ServerSocket". My program looks exactly like the demo only it it forks processes.
// libraries
#include <signal.h>
#include <string>
#include <iostream>
// headers
#include "serversocket.hpp"
#include "socketexception.hpp"
#include "config.hpp"
using namespace std;
void sessionHandler( ServerSocket );
int main ( int argc, char** argv )
{
configClass config; // this object handles command line args
config.init( argc, argv ); // initialize config with args
pid_t childpid; // this will hold the child pid
signal(SIGCHLD, SIG_IGN); // this prevents zombie processes on *nix
try
{
ServerSocket server ( config.port ); // create the socket
cout << "server alive" << "\n";
cout << "listening on port: " << config.port << "\n";
while ( true )
{
ServerSocket new_client; // create socket stream
server.accept ( new_client ); // accept a connection to the server
switch ( childpid = fork() ) // fork the child process
{
case -1://error
cerr << "error spawning child" << "\n";
break;
case 0://in the child
sessionHandler( new_client ); // handle the new client
exit(0); // session ended normally
break;
default://in the server
cout << "child process spawned: " << childpid << "\n";
break;
}
}
}
catch ( SocketException& e ) // catch problem creating server socket
{
cerr << "error: " << e.description() << "\n";
}
return 0;
}
// function declarations
void sessionHandler( ServerSocket client )
{
try
{
while ( true )
{
string data;
client >> data;
client << data;
}
}
catch ( SocketException& e )
{
cerr << "error: " << e.description() << "\n";
}
}
So my question is, can I not access the IP of the client currently connected to the socket? If it has to be modified for that functionality, what would the cleanest way to do it be?
Thanks for suggestions
I was able to add these 2 functions that allowed me to get the IP only from the scope of main like this:
server.get_ip( new_client );
but what I'd really like is to get it like this new_client.ip();
here's my 2 functions, maybe you can help me further:
std::string Socket::get_ip( Socket& new_socket )
{
char cstr[INET_ADDRSTRLEN];
std::string str;
inet_ntop(AF_INET, &(m_addr.sin_addr), cstr, INET_ADDRSTRLEN);
str = cstr;
return str;
}
std::string ServerSocket::get_ip( ServerSocket& sock )
{
return Socket::get_ip( sock );
}

The Socket class you are using has a private data member:
sockaddr_in m_addr;
This contains the info of the client connected to the socket. You can get the human-readable address with:
char str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(m_addr.sin_addr), str, INET_ADDRSTRLEN);
As for the changes you need to make, either make m_addr public (not recommended) or add a member function that can return a string based on the above code sample.

Related

Unable to receive UDP message packets through receiveFrom API of Poco Library. It doesnt return from the receiveFrom API

Able to send UDP message to a particular IP port using Poco Lib socket communication, But unable to receive the UDP message as it is getting stuck at receiveFrom API of DatagramSocket as in below code.
I am sending message every second and also have to receive acknowledgement every second, for that i have timer , Client and Server Threads running parallelly. The problem here is I am unable to receive the UDP packets which are being captured on wireshark. It is getting stuck at receiveFrom.
Please find below Client Server and main files.
` Server.hpp
#pragma once
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/DatagramSocket.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/MulticastSocket.h"
#include "Poco/RunnableAdapter.h"
#include "Poco/Thread.h"
#include <cstring>
#include <iostream>
using namespace std;
using namespace Poco;
using namespace Poco::Net;
struct Server
{
int bufferSize;
SocketAddress sockets;
static bool debugModeEnabled;
Server() :
bufferSize(1024) { //sockets = SocketAddress(10000);
}
Server(const UInt16& port, const int& bufferSize)
{
sockets = SocketAddress(port);
this->bufferSize = bufferSize;
}
void receiveMessages()
{
char buffer[bufferSize];
try
{
Poco::Net::DatagramSocket datagram(sockets);//(socket);
datagram.bind(sockets);
cout << "Server started socket" << endl;
while (!datagram.available())
{
SocketAddress sender;
cout << "Server started socket 2" << endl;
int size = datagram.receiveFrom(buffer, bufferSize, sender);
//int size = datagram.receiveBytes(buffer, bufferSize);
cout << "received bytes size" << size << endl;
buffer[size] = '\0';
//std::string str(buffer);
//cout << (debugModeEnabled ? (sender.toString() + ": ") : "- ") << buffer << endl;
cout << "received: " << size << buffer << endl;
//cout << buffer << "Server adasdasd" << endl;
if (string(buffer) == "\\end")
{
//cerr << "\nUser: " << sender.toString() << " ended connection" << endl;
datagram.close(); // Closes the server
}
}
}
catch (const Poco::Exception& exc)
{
std::cerr << exc.displayText() << std::endl;
}
}
};
bool Server::debugModeEnabled = false;
`
`Client.hpp
#pragma once
#include "Poco/Net/DatagramSocket.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/RunnableAdapter.h"
#include "Poco/Thread.h"
#include <iostream>
#include <string>
using namespace std;
using namespace Poco;
using namespace Poco::Net;
struct Client
{
SocketAddress socket;
string str;
// By default the client connects to itself
Client() { socket = SocketAddress("127.0.0.1", 10000); }
Client(const Poco::Net::IPAddress& IP, const UInt16& port, const string& val) :
str(val)
{
socket = SocketAddress(IP, port);
}
void sendMessages()
{
DatagramSocket datagram;
datagram.connect(socket);
string message = str;
//cout << "sending: " << hex << hexify(message) << endl;
unsigned int bytes_sent = 0;
while (!datagram.available())
{
//getline(cin, message);
//bytes_sent = datagram.sendBytes(message.data(), static_cast<int>(message.size()));
bytes_sent = datagram.sendTo(message.data(), static_cast<int>(message.size()),socket);
cout << "number of bytes sent: " << std::dec << bytes_sent << endl;
if (bytes_sent >= message.size())
{
datagram.close();
}
}
}
string IP() { return socket.host().toString(); }
UInt16 port() { return socket.port(); }
static void sendMessage(const Poco::Net::IPAddress& IP, const UInt16& port, const string& message)
{
SocketAddress socket(IP, port);
DatagramSocket datagram;
datagram.connect(socket);
datagram.sendBytes(message.data(), int(message.size()));
}
};
`
` main.cpp
int bufferSize = 1024;
int exit_status = 0;
Client client(IP, ciPort, str);
Server server(mdilPort, bufferSize);
RunnableAdapter<Client> clientRunnable(client, &Client::sendMessages);
RunnableAdapter<Server> serverRunnable(server, &Server::receiveMessages);
Thread clientThread, serverThread;
// Client::sendMessage(IP, ciPort, "hello!!");
try
{
Timer t = Timer();
t.setInterval([&]() {
cout << "client Tick" << endl;
// pApp->SendIndications();
clientThread.start(clientRunnable);
clientThread.join();
},
1000);
t.setInterval([&]() {
cout<< "server Tick" << endl;
serverThread.start(serverRunnable);
serverThread.join();
},
1000);
t.setTimeout([&]() {
std::cout << "Hey.. After 30s. But I will stop the timer!" << std::endl;
t.stop();
exit(exit_status);
},
30000);
std::cout << "I am Timer" << std::endl;
while (true); // Keep main thread active
}
catch (...)
{
std::cout << "catched exception" << std::endl;
//return -1;
}
`
I tried the conventional Socket Programming API's to receive the UDP packets but there also it is getting stuck at receiveFrom API. also tried running both client and server on different process to make sure there is no issue with the multi threading synchronization, but both the approach didnt help. I am able to capture the response at Wireshark but unable to receive on the application side using Poco Lib socket API's. Also allowed visual studio code through firewall as well

How to Send messages between server and client using C++ standard library networking TS

I have tried following the tutorial from boost, however the API is not identical so I have had to guess some parts.
My attempt so far is shown bellow:
#include <iostream>
#include <experimental/internet>
#include <experimental/socket>
#include <thread>
#include <chrono>
using namespace std::experimental;
int main(int argc, char* argv[])
{
std::thread server = std::thread([]()
{
std::cout << "Starting server" << std::endl;
net::io_context context;
net::ip::tcp::endpoint endpoint{net::ip::tcp::v4(), 1234};
net::ip::tcp::acceptor acceptor{context, endpoint};
acceptor.non_blocking(true);
std::cout << "opened server on " << endpoint << std::endl;
std::error_code error;
net::ip::tcp::socket socket(context);
while (true)
{
socket = acceptor.accept(error); //accept connections
if (!error) //if connected with a client
{
std::cout << "Connected to client!" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
std::string data = "Hello World!";
net::const_buffer buf(&data, sizeof(data));
socket.send(buf);
std::cout << "Sent data!" << std::endl;
while(true) {}
}
}
});
std::thread client = std::thread([]()
{
net::io_context context;
net::ip::tcp::socket socket(context);
net::ip::tcp::endpoint server{net::ip::tcp::v4(), 1234};
std::error_code error;
while(true)
{
socket.connect(server, error); //attempt to connect
if (!error) //if connected
{
std::cout << "Connected to server!" << std::endl;
net::mutable_buffer buf;
while(buf.size() == 0)
{
socket.receive(buf);
}
std::cout << "Received data!" << std::endl;
std::cout << buf.data() << std::endl;
while(true) {}
}
}
});
server.join();
return 0;
}
The sever and client connect, but the message is not received by the client. The output from the program above is:
Starting server
opened server on 0.0.0.0:1234
Connected to server!
Connected to client!
Sent data!
And then it waits forever.
How do I get the socket to correctly receive the data?
This
std::string data = "Hello World!";
net::const_buffer buf(&data, sizeof(data));
is wrong. You want to send content of data string, not its internal bytes. &data gives you a pointer to underlying data of string instance, not its content. If you want to create buffer which represents content of data you can do:
const std::string data = "Hello World!";
net::const_buffer buf = net::buffer(data);
This
net::mutable_buffer buf;
while(buf.size() == 0)
{
socket.receive(buf);
}
gives you infinite loop because initial size of buf is 0, so receive reads 0 bytes and returns. Then while condition is checked, buf's size is still 0, and the loop goes on.
Before calling receive you need to specify the size of buffer - it indicates how many bytes must be read. You are sending Hello World! so
std::string msg;
msg.resize(12); // prepare space for incoming data
net::mutable_buffer buf = net::buffer(msg);
socket.receive(buf);
std::cout << "I got: " << msg << std::endl;

Read/print socket ouput while waiting on cin (w/o multithreading)

i have a client program that connects to a server via a TCP socket, below:
int main ( )
{
std::cout << "HunterChat client starting up" << std::endl;
std::string cmd;
std::string reply;
bool cont = true;
ClientSocket client_socket ( "localhost", PORT );
try {
while(cont) {
try {
std::cout << ">> ";
// std::getline(std::cin,cmd);
gets(cmd);
if(cmd.compare("logout") == 0) {
cont = false;
break;
}
client_socket << cmd;
client_socket >> reply;
std::cout << reply << std::endl;
}
catch ( SocketException& e) {
std::cout << "Exception was caught:" << e.description() << "\n";
}
}
}
catch ( SocketException& e ) {
std::cout << "Exception was caught:" << e.description() << "\n";
}
return 0;
}
ClientSocket is a custom class that lets me set up and use the TCP connection; the stream operator is overloaded with, the following code:
int status = ::send ( m_sock, s.c_str(), s.size(), MSG_NOSIGNAL );
if ( status == -1 )
{
return false;
}
else
{
return true;
}
The TCP connection itself is working fine, so I won't clutter the post up with more of it. The problem is that one of the available commands involves sending input to a client instance while said client is still waiting for cin input. This means that the server messages only get read and written when I type something into cin. I'm trying to avoid using multithreading, so is there any way to allow cin to be interrupted without it?
Well, you could use a loop and the function kbhit() to check for user input if you really want to. However, threading seems to me such a better solution.
#include <conio.h>
#include <iostream>
using namespace std;
int main()
{
while(1)
{
if(kbhit())
{
char x = getch();
// ...
}
// check messages asynchronously here
}
}

ASIO Client Server Connects Fine on the same PC, but Fails across a Local Network

I'm going to include all the relevant portions of code, but I'm pretty sure the problem is with my network, not with my code, since my code works perfectly fine if I loopback on a single computer. Nevertheless, if you see any immediately obvious errors in the code, I'd like to know.
Reference basic_server code (only the relevant parts):
connection_id basic_server::start_listening(const std::string & ip_address, const std::string & port) {
asio::ip::tcp::resolver resolver(*service);
asio::ip::tcp::resolver::query query(ip_address, port);
asio::ip::tcp::endpoint endpoint = *(resolver.resolve(query));
connection_id id(get_seed());
while (connections.contains(id)) {
std::this_thread::yield();
id = get_seed();
}
connections[id] = connection_ptr(new connection(id, *service, ip_address, port));
connection_ptr conn = connections[id];
conn->state = listening;
if (!acceptor->is_open()) {
acceptor->open(endpoint.protocol());
}
if (current_ip != ip_address || current_port != port) {
acceptor->bind(endpoint);
current_ip = ip_address;
current_port = port;
}
acceptor->listen(asio::socket_base::max_connections);
acceptor->async_accept(
conn->get_socket(),
std::bind(
&basic_server::connect,
this,
std::placeholders::_1,
id
)
);
return id;
}
connection_id basic_server::start_connecting(const std::string & ip_address, const std::string & port) {
asio::ip::tcp::resolver resolver(*service);
asio::ip::tcp::resolver::query query(ip_address, port);
asio::ip::tcp::endpoint endpoint = *(resolver.resolve(query));
connection_id id(get_seed());
while (connections.contains(id)) {
std::this_thread::yield();
id = get_seed();
}
connections[id] = connection_ptr(new connection(id, *service, ip_address, port));
connection_ptr conn = connections[id];
conn->state = connecting;
conn->get_socket().async_connect(
endpoint,
std::bind(
&basic_server::connect,
this,
std::placeholders::_1,
id
)
);
return id;
}
Reference Server code:
#include "../../Utilities/BasicServer/Basic Server.h"
int main() {
server::basic_server this_server;
server::connection_id id = this_server.start_listening("::1", "6118");
const std::set<server::connection_state> valid_states = { server::open, server::listening, server::connecting };
while (this_server.connection_status(id) == server::listening) std::cout << "Waiting for Client.\r";
std::cout << std::endl;
while (true) {
if (valid_states.find(this_server.connection_status(id)) == valid_states.end()) {
std::cout << "We've lost connection with the client." << std::endl;
break;
}
server::data_pair data;
bool successful_read = this_server.read_from_queue(data);
if (!successful_read) {
std::this_thread::yield();
continue;
}
server::connection_id read_id = data.first;
server::data_vector & read_vector = data.second;
std::string line;
line.resize(70);
std::copy(read_vector.begin(), read_vector.begin() + std::min(70ull, read_vector.size()), line.begin());
std::cout << line << std::endl;
}
system("pause");
return 0;
}
Reference Client Code (not much different from the Server code):
#include "../../Utilities/BasicServer/Basic Server.h"
int main(int argc, char ** argv) {
server::basic_server this_client;
std::string ip_address;
if (argc < 2) return 0;
ip_address = argv[1];
server::connection_id id = this_client.start_connecting(ip_address, "6118");
const std::set<server::connection_state> valid_states = { server::open, server::listening, server::connecting };
while (this_client.connection_status(id) == server::connecting) std::cout << "Connecting to Server with IP address \"" << ip_address << "\"\r";
std::cout << std::endl;
if (this_client.connection_status(id) == server::open) {
std::cout << "We're connected!" << std::endl;
}
else {
std::cout << "Unable to connect." << std::endl;
system("pause");
return 0;
}
while (true) {
if (valid_states.find(this_client.connection_status(id)) == valid_states.end()) {
std::cout << "We've lost connection." << std::endl;
break;
}
std::string line;
std::getline(std::cin, line);
std::cout << "Attemping to write \"" << line << "\"" << std::endl;
this_client.write_to_connection(id, &line.front(), line.size() * sizeof(unsigned char));
if (line == "") break;
}
system("pause");
return 0;
}
So the basic gist of my problem is that when I try to connect from one computer to another (via my local network) the connection fails. If I run the server and client on the same computer, it works with no problems. I've tried all of the following:
pinging the receiving/sending computers to verify they see each other: they do.
running tracert to check the connection: they reach each other in one hop, no outside connections involved.
swapping between using IPv6 and IPv4 (my router supports both) to attempt to connect: I determined that when looping back, using IPv6 as the server binding endpoint won't work if the client uses the IPv4 loopback address, and vice-versa, but if they're both using IPv6 or IPv4 it works fine on the loopback. None of these work across different computers.
Any thoughts as to what's going wrong?
As we found in the comments, the problem was network firewall plus listening localhost only. Listening on any IP is available when you listen 0.0.0.0 IP or if you use endpoint, create it without specifying listen IP address: ip::tcp::endpoint( ip::tcp::v4(), 6118 )

C++ multi client server

sry but my english.
it's a simple application client-server written in C++
the operating system is OpenSUSE 13.1 Linux
I do not know how to do multi client
if you could help me I would appreciate much
All this is work with only one client
i need help, thanks
This is the
Server.cpp
#include "ServerSocket.cpp"
#include "SocketException.h"
#include <string>
#include <iostream>
int main ()
{
std::cout << "running....\n";
try
{
// Create the socket
ServerSocket server ( 2020 );
while ( true )
{
ServerSocket new_sock;
server.accept ( new_sock );
try
{
while ( true )
{
std::string data;
new_sock >> data;
std::cout << "in::" << data << std::endl;
new_sock << data; // Respuesta
}
}
catch ( SocketException& ) {}
}
}
catch ( SocketException& e )
{
std::cout << "Exception was caught:" << e.description() << "\nExiting.\n";
}
return 0;
}
This is the
Client.cpp
#include "ClientSocket.cpp"
#include "SocketException.h"
#include <iostream>
#include <string>
int main ( )
{
try
{
ClientSocket client_socket ( "localhost", 2020 );
std::string reply;
try
{
std::string Envio = "";
while(Envio != "Exit")
{
getline(std::cin, Envio);
client_socket << Envio;
client_socket >> reply;
}
}
catch ( SocketException& ) {}
std::cout << "We received this response from the server:\n\"" << reply << "\"\n";;
}
catch ( SocketException& e )
{
std::cout << "Exception was caught:" << e.description() << "\n";
}
return 0;
}
Your server stops accepting connections after the very first one, and enters an infinite loop (the inner while (true)).
How to fix this depends on how your server should serve the clients. If it accepts connection, receives request, sends reply and then forgets about the client, then you do not need the inner while (true): just << and >> operations (probably you should also close the connection), and then proceed to the next accept. If you need several connections to be alive, consider making your application multi-threaded (maybe spawning a new thread for each connection if number of connections is not large).