Why does socket_base not have a send() method? Basically, I would like to use boost::asio's sockets like linux socket descriptors: whether the underlying socket is UDP or TCP it doesn't matter, you can call read(), write(), sendto(), etc... on them.
Is there a more proper solution than just writing a wrapper class around asio's udp & tcp socket classes?
You need to use a particular type of socket, like boost::asio::ip::tcp::socket, which is a stream-based TCP socket, or boost::asio::ip::udp::socket, which is for datagrams. The socket_base class is simply a base class which stores common functionality. The actual socket classes contain all the transfer functions you're looking for, like send and receive functions.
As you can see in the documentation, each socket type has send and receive functions.
Related
In boost.asio, there is a class called an acceptor. The acceptor is used to listen for connection requests on a specific endpoint and open a socket in response to a request.
There are three acceptor constructors I am interested in.
construct an acceptor without opening or binding
explicit basic_socket_acceptor(
const executor_type & ex);
construct an acceptor and open it
basic_socket_acceptor(
const executor_type & ex,
const protocol_type & protocol);
construct an acceptor, open it, and bind it to an endpoint
basic_socket_acceptor(
const executor_type & ex,
const endpoint_type & endpoint,
bool reuse_addr = true);
1 and 3 both make sense. 1 constructs the acceptor in the C++ sense: allocate memory on the stack, maybe initialize some variables, etc. 3 specifies the endpoint that the acceptor should listen on. Incoming connection requests addressed to the endpoint will be accepted and a connection will be created on a new socket. 2, however, appears to be a middle ground that allows you to set a "protocol type."
I want to say that that "2 allows you to specify more member variables (the protocol) than 1 and less member variables (e.g., IP address and port number) than 3." However, I don't know if it does anything "extra" over setting some member variables (does it engage with the OS or the NIC?).
What does it mean to open an acceptor?
It opens the socket, indeed.
I chose to talk about the constructor to differentiate between 1, 2, and 3. A question about the member function open would probably have the same answer as this question.
The question then becomes just what does ::socket do (https://pubs.opengroup.org/onlinepubs/009604499/functions/socket.html):
The socket() function shall create an unbound socket in a communications domain, and return a file descriptor that can be used in later function calls that operate on sockets
So for your practical understanding, it allocates and initializes in-kernel resources[1].
Note
Technically there is no difference between an "acceptor" socket and a "connection" socket. Asio distinguishes them conceptually so it's easier to use them right. The reverse question might offer enlightenment: Design rationale behind that separate acceptor class exists in ASIO
[1] on most operating systems, userland TCP stacks exists though
Do you know the underlying logic of accepting incoming networking connections with BSD sockets?
The steps, if you write them manually, are:
open a socket with socket()
just like opening a file, and you get an integer descriptor you can use with read(), write(), close() etc.
bind the socket to a network address with bind()
unlike a file, the socket descriptor is not associated with anything outside your process until you do this
tell the OS you want to listen for connections on this socket, with listen()
until this point, it could still be used as an outgoing connection, although it's unusual to bind the source address explicitly
start accepting incoming connection requests by calling accept()
So when you open an acceptor, you're asking the OS for a socket and saving the descriptor to a member variable.
When you bind an acceptor, you're just asking the OS to link that socket to an address (but there may be a member variable tracking its state as well, so the acceptor remembers this has been done).
Note that the "middle ground" passes a protocol type, which is needed to open a socket (it corresponds exactly to the arguments to socket()), but it doesn't have an address (or endpoint), so it can't bind that socket yet.
boost::asio library provides support for SSL encrypted traffic over sockets by wrapping socket objects in boost::asio::ssl::stream decorator class template. For example:
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> sslSocket;
Some operations of tcp::socket are not supported by ssl::stream. Calling ssl::stream::next_layer method returns reference to wrapped object and this way not supported by ssl::stream operations can be performed directly on wrapped object.
However it seems logical for me that performing read and write operations directly on wrapped socket object bypasses SSL decryption and encryption and for correct SSL behavior read and write on sslSocket must be performed directly over wrapping ssl::stream object.
Is this right or I can freely perform read and write operation on wrapped object?
Not only does using the underlying socket bypass the encryption, it bypasses all of the protocol. Including handshakes, (re)negotiation, side-channels, keepalive etc.
There's no actual guarantee that it would work at all. The only thing you can expect to work is when you use the underlying socket before initializing any SSL operation for the first time.
Beyond that, it's like writing random data to the filedescriptor of a socket that is managed by openssl.
We have a boost asio based networking code, which connects to a remote side.
The local side could be either a tcp4 socket or a unix socket.
Is there a typename to use that could hold both of these type of boost sockets? (e.g. something like a base class for both?).
Currently our code use
boost::asio::generic::stream_protocol::socket for tcp socket, and
boost::asio::local::stream_protocol::socket for a unix socket.
Actually, there's a dedicated ip::tcp::socket type for tcp sockets.
As for generic::stream_protocol::socket, it is the universal stream socket type that accepts socket protocol and family in run-time, so you can use it for the both types you need:
generic::stream_protocol::socket ipc(io_, generic::stream_protocol(AF_UNIX, 0));
generic::stream_protocol::socket tcp(io_, generic::stream_protocol(AF_INET, IPPROTO_TCP));
I working on a client/server application using boost asio, specifically boost::asio::ip::tcp::socket to connect and transfer data. Right now I am using boost::asio::async_read to recive a certain amount of bytes. Until now, in all cases I know how many bytes I want to receive, before calling my handler. Therefore I don't see a reason to use the sockets meber function read_some. But I wonder why there is no "async_read" member function of boost::asio::ip::tcp::socket but only the free one.
So my question is: Are there conceptual or technical reasons why there is a read_some member function but no readmember function, or did "Boost just forgot to implement it" ?
All of the streaming interfaces in Asio provide both read_some and async_read_some moethods. This is true for the TCP sockets, SSL streams, and Serial ports. The implementation of read, read_until, and their async cousins all have the same implementations, based on using the read_some method. The read function is written as a generic template, that can use the read_some method on its first argument to perform the call as you requested.
There are some C++ advocates that recommend using non-friend non-member functions whenever possible, so as to minimize the changes when a class implementation changes. read_some is the interface, and read is just a wrapper that adds blocking in the case of partial reads for a variety of different sources.
As Dave S says, you will find these as external helper functions in boost\boost\asio\read.hpp
If you look at the boost 1.52 asio examples, the blocking_tcp_echo_client and blocking_tcp_echo_server examples use the blocking form of the write(). The example uses read_some() because it does not pre-know the size ... however the write function is completely analogous to your read question and also exists as a helper write.hpp in the same place as read.hpp.
Basically:
tcp::socket s(io_service);
char buff[LENGTH];
boost::asio::write(s, boost::asio::buffer(buff, LENGTH));
boost::asio::read(s, boost::asio::buffer(buff, LENGTH));
1) How can i get raw socket fd from boost ip::tcp::socket type ??
2) Can i able to read from ip::tcp::socket type of boost library and write through normal send(fd...) system call ? Is that feasible. Can some one help me..
Thanks in advance.
Regards,
Suyambu
You should be able to get the socket fd from ip::tcp::socket::native().
Get the native socket representation.
native_type native();
This function may be used to obtain the underlying representation of the socket. This is intended to allow access to native socket functionality that is not otherwise provided.
I would imagine you can read through this class and write through send since the buffers should be segregated but you'll need to test it.