I'm trying to send data to my own local port using UDP packet.
For this I use boost::asio
#include <iostream>
#include <boost/asio.hpp>
#include <boost/system/error_code.hpp>
using boost::asio::ip::udp;
using boost::asio::ip::address;
boost::asio::io_service _ioServiceOut;
std::shared_ptr<udp::socket> _socketOut;
std::shared_ptr<udp::endpoint> _endpointOut;
static int PortOut = 32676;
static std::string Loopback = "127.0.0.1";
int main()
{
_endpointOut = std::make_shared<udp::endpoint>(address::from_string(Loopback), PortOut);
_socketOut = std::make_shared<udp::socket>(_ioServiceOut, *_endpointOut.get());
_socketOut->send_to(
boost::asio::buffer("0"), *(_endpointOut.get())
);
return 0;
}
The problem is, it sends from 32676 to 32676 and my other application that is listening to this port, can't receive the message then.
When writin a similar application in C#, the Net.Socket assigns a random port as the outcoming one.
How can I achieve the same effect with boost::asio?
So, thanks to tkausl I figured out the problem is the Output socked initialization. If you want your system to assing you a free port, just create a new endpoint setting the port to 0.
_socketOut = std::make_shared<udp::socket>(_ioServiceOut, new udp::endpoint(address::from_string(Loopback), 0));
Related
I am learning Socket-programming in C++. I understand that the socket must bind to the server address and in the client side, there is an internal bind() when connect() is called. The server listens on the port specified in sin_port of the struct sockaddr_in.
But when I specify the same port to sin_port of the struct sockaddr_in in client, does that mean that both client and server are bound on the same port. I hope this is the part, I am going wrong.
Here are the codes :
SERVER :
#include<iostream>
#include<sys/socket.h>
#include<sys/types.h>
#include<unistd.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<netdb.h>
using namespace std;
int main(){
int sockid=socket(AF_INET,SOCK_STREAM,0);
if(sockid<0){
cout<<"failed socket";
}
struct sockaddr_in server, client;
int cz=sizeof(client);
server.sin_family=AF_INET;
server.sin_port=htons(9999);
server.sin_addr.s_addr=htonl(INADDR_ANY);
if(bind(sockid,(struct sockaddr*)&server, sizeof(server))<0){
cout<<"Failed binding";
return 0;
}
cout<<"binded\n";
if(listen(sockid,3)<0){//
cout<<"\nFailed Listening";
return 0;
}
int client_socket=accept(sockid,(struct sockaddr*)&client, (socklen_t*)&cz);
if(client_socket<0){
cout<<"Failed connecting";
return 0;
}
cout<<"Connected....\n";
char buff[1024]={0};
cout<<"enter message: ";
cin>>buff;
if(send(client_socket,buff,strlen(buff),0)<0){
cout<<"\nFailed sending\n";
return 0;
}
cout<<"Message sent";
return 0;
}
CLIENT
#include<arpa/inet.h>
#include<netdb.h>
#include<iostream>
#include<sys/socket.h>
#include<sys/types.h>
#include<unistd.h>
#include<netinet/in.h>
using namespace std;
int main(){
int sockid=socket(AF_INET,SOCK_STREAM,0);
if(sockid<0){
cout<<"failed socket";
}
struct sockaddr_in client;
int cz=sizeof(client);
client.sin_family=AF_INET;
client.sin_port=htons(9999);
client.sin_addr.s_addr=INADDR_ANY;
int server_socket=connect(sockid,(struct sockaddr*)&client, sizeof(client));
if(server_socket<0){
cout<<"Failed connecting";
return 0;
}
cout<<"Connected\n";
char buff[250];//
recv(sockid,buff,1024,0);
cout<<"Received msg: "<<buff;
return 0;
}
The server should bind to the same port the client connects to. That way, the server and client will be talking to each other. Typically, the server binds to a well-known port and listens. The client doesn't call bind, which results in it binding to a random port. But it does call connect to connect to the server's well-known port. The server listens on, sends from, and receives on the well-known port. The client connects to, sends to, and receives from the well-known port.
Also, don't actually ever do this:
recv(sockid,buff,1024,0);
cout<<"Received msg: "<<buff;
TCP is not a message-based protocol. The recv function, when called on a TCP socket, does not receive a message nor even know what a message is. When you call a stream's operator<< and pass it a char *, like you are, it expects that char * to point to a valid C-style string, which is not assured in this code. Worse, you've ignored the return value from recv which is the only way to know how many bytes you received.
There's a similar issue here:
if(send(client_socket,buff,strlen(buff),0)<0){
You don't send the terminating zero byte, so there is no way for the receiver to figure out where the message ends other than by the fact that you then close the connection. This works only in the exact case where you want to send precisely one message and then close the connection without any possibility of a response. And, in this case, the receiver needs to keep calling recv until it gets an indication that the connection has been closed before it considers itself to have received a message.
I am currently trying to communicate with a PLC by using Modbus/TCP but even thought I can read the Modbus frame send by the PLC I must give the Modbus response to port 502 and the stream I use send to the port used by the PLC to send the frame. I tried using two stream to receive and send but when i close the first one the PLC get that as a timed out communication and then refuse the second connection.
If it can help you here is the code I use but for now it barely does anything else than allowing me to test the connection.
#define _WIN32_WINNT 0x0501
#include <iostream>
#include <boost/asio.hpp>
#include <boost/system/config.hpp>
#include <string>
using namespace std;
using boost::asio::ip::tcp;
int main()
{
boost::asio::io_service io_service;
tcp::endpoint endpoint(tcp::v4(), 502);
tcp::acceptor acceptor(io_service, endpoint);
while (1)
{
int i =0;
string buff;
char buf[30];
tcp::iostream stream;
tcp::iostream s("192.168.10.150", "502");
acceptor.accept(*stream.rdbuf());
getline(stream, buff);
cout<<buff<<endl;
s <<buff;
}
}
If you have any suggestion.
I'm trying to build an application that:
a) Runs an FDM (flight dynamics model) internally, and manages the flight data
b) Accepts connections on a TCP socket
c) Serves the flight data over said socket.
I've currently managed to get a simple string sent over TCP on my a local socket using the examples/tutorials on the Boos::ASIO website here: http://www.boost.org/doc/libs/1_56_0_b1/doc/html/boost_asio/tutorial.html
My trouble is simply that the connection closes after a single string is written, and I don't know how to keep the connection open and continuously send the data until the simulation is finished (or a stop signal is sent from the listening application).
I also have the FDM working (currently using JSBSim, and borrowing heavily from their included sample code), and can print flight data to stdout no problem. The Boost:ASIO documentation shows a few examples on how to build a server that constantly listens for messages received from the client, but none that send a stream of data out.
To send a stream of data out, you can use the free functions with boost::asio::streambuf.
Here's a simple demo that sends its own source to each client:
#include <boost/asio.hpp>
#include <boost/make_shared.hpp>
#include <boost/function.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
#include <fstream>
#include <iostream>
namespace io = boost::asio;
namespace ip = io::ip;
using boost::system::error_code;
using boost::make_shared;
using ip::tcp;
void start_accept(io::io_service& svc, tcp::acceptor& acc) {
// per-connection lifetimes:
auto sock = make_shared<tcp::socket>(svc);
acc.async_accept(*sock, [sock,&svc,&acc](error_code ec) {
if (!ec)
{
std::cout << "connection from " << sock->remote_endpoint() << "\n";
// copy source file to buffer data
auto data = make_shared<io::streambuf>();
std::ostream(data.get()) << std::ifstream("main.cpp").rdbuf();
// now write the whole story
io::async_write(*sock, *data, [sock,data/*keep alive*/](error_code ec, size_t transferred){});
// accept new connections too
start_accept(svc, acc);
}
});
}
int main()
{
io::io_service svc;
tcp::acceptor acc(svc, tcp::endpoint(ip::address(), 6767));
start_accept(svc, acc);
svc.run();
}
Note that for simplicity I put the full buffer in memory first, assuming you can do that (you said "and can print flight data to stdout no problem"). So, you could just write different things to the stream (the ostream line in my example).
I'm working on an application that needs to perform network communication and decided to use the poco c++ libraries. After going through the network tutorial I can't seem to find any forms of validation on establishing a network connection.
In the following example a client tries to connect to a server using a tcp socket stream:
#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/SocketStream.h"
#include "Poco/StreamCopier.h"
#include <iostream>
int main(int argc, char** argv)
{
Poco::Net::SocketAddress sa("www.appinf.com", 80);
Poco::Net::StreamSocket socket(sa);
Poco::Net::SocketStream str(socket);
str << "GET / HTTP/1.1\r\n"
"Host: www.appinf.com\r\n"
"\r\n";
str.flush();
Poco::StreamCopier::copyStream(str, std::cout);
return 0;
}
However, I couldn't find any information related to:
Error checking(what if www.appinf.com is unavailable or doesn't exist for that matter)
The type of exception these calls may raise
The only mention is that a SocketStream may hang if the receive timeout is not set for the socket when using formated inputs.
How can I check if a host is alive and may set up a tcp connection, implement a method such as:
void TCPClient::connectTo(std::string host, bool& connected, unsigned int port) {
std::string hi = "hi";
Poco::Net::SocketAddress clientSocketAddress(host, port);
Poco::Net::StreamSocket clientStreamSocket;
// try to connect and avoid hang by setting a timeout
clientStreamSocket.connect(clientSocketAddress, timeout);
// check if the connection has failed or not,
// set the connected parameter accordingly
// additionally try to send bytes over this connection
Poco::Net::SocketStream clientSocketStream(clientStreamSocket);
clientSocketStream << hi << std::endl;
clientSocketStream.flush();
// close the socket stream
clientSocketStream.close();
// close stream
clientStreamSocket.shutdown();
}
Below is the following basic socket code I came up with:
//General includes:
#include <iostream>
#include <stdio.h>
#include <string>
//Network related includes:
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
//Target host details:
#define PORT 1234
#define HOST "74.74.74.74"
using namespace std;
//Function prototypes:
string MessageFormat(int, char**);
void MessageSend(string);
int main(int argc, char *argv[])
{
//Parse arguments and format message:
string message = MessageFormat(argc, argv);
//Send the message out:
MessageSend(message);
return 0;
}
string MessageFormat(int argc, char *argv[])
{
//Massage the command line parameters
// into my desired payload format.
return message;
}
void MessageSend(string message)
{
int sd, ret;
struct sockaddr_in server;
struct in_addr ipv4addr;
struct hostent *hp;
sd = socket(AF_INET,SOCK_DGRAM,0);
server.sin_family = AF_INET;
inet_pton(AF_INET, HOST, &ipv4addr);
hp = gethostbyaddr(&ipv4addr, sizeof ipv4addr, AF_INET);
//hp = gethostbyname(HOST);
bcopy(hp->h_addr, &(server.sin_addr.s_addr), hp->h_length);
server.sin_port = htons(PORT);
connect(sd, (const sockaddr *)&server, sizeof(server));
send(sd, (char *)message.c_str(), strlen((char *)message.c_str()), 0);
}
This is quite basic, and does in fact work. HOWEVER, it's sending UDP packets instead of TCP packets, so the target host expecting TCP rejects these. Also, by inspecting connect/send values and watching my interfaces with ngrep I can 100% verify the packet is going out, so that's not the issue.
I'm only interested in modifying what I have, not creating a full featured server with boost asio. How can I tweak this so that it operates in terms of TCP instead of UDP?
Following are changes you need to make to transfer data via TCP
While creating socket pass correct parameters .In above example you passed SOCK_DGRAM instead pass SOCK_STREAM.
After binding server should go into listen mode (check the manual page of listen)
while Client Side should connect after socket creation.
Then accept in server side after listen.
Final Read and write to transfer data
Diagram attached will give you a clear picture of TCP connection
You can check manual pages for detailed info on all functions or refer beej's guide for socket programming ( use this link )
Replace SOCK_DGRAM with SOCK_STREAM.
Also, read the manual or get a good book.