fpagliughi / sockpp

Modern C++ socket library.
BSD 3-Clause "New" or "Revised" License
769 stars 126 forks source link

Can I clone a udp_socket #73

Closed tongxiangzheng closed 1 year ago

tongxiangzheng commented 1 year ago

Since I can use clone() to copy a tcp_socket or tcp_connect, I want to do the same for udp_socket For example, I want to have one thread to read from a udp_socket and another thread to write to this udp_socket Here is a demo:

const int BUF_SIZE = 512;
const string host = "";//the target
const in_port_t port = 12345;
void listener(sockpp::udp_socket sock) {
    string s;
    s.resize(BUF_SIZE);
    while (true) {
        int n = sock.recv(&s[0], BUF_SIZE);
        cout << s.substr(0, n) << endl;
    }
}
void sender(sockpp::udp_socket sock) {
    string s;
    while (true) {
        cin >> s;
        sock.send_to(s, {host, port});
    }
}
int main() {
    sockpp::initialize();
    sockpp::udp_socket sock;
    sock.connect({host, port});
    std::thread thr(listener, sock.clone());
    sender(std::move(sock));
}

But this example fails to compile. In order to make it work, I consult stream_socket.h and modified datagram_socket.h. Specifically, I tried adding a function like below in class datagram_socket:

datagram_socket clone() const {
    auto h = base::clone().release();
    return datagram_socket(h);
}

And a function below in class datagram_socket_tmpl:

datagram_socket_tmpl(datagram_socket&& sock)
    : base(std::move(sock)) {}

It seems to work fine under Windows, but I didn't do a rigorous test. Is there a bug in this method, and is there a better way to deal with the problem?

fpagliughi commented 1 year ago

That should be fine. The fact that I left it out of the datagram sockets it likely just because I didn't think to add it. I personally haven't used datagram sockets that much with this library.

In general, it's safe to to share an OS socket where one thread only reads and the other thread only writes. This library, however caches the last error in the object, so it isn't safe to share a sockpp::socket across threads or else you will likely corrupt the error reporting. The other problem would also be around ownership. Only one thread could own the object, and when it ended it would close the socket. This would be a problem if the seond thread were still running.

This library works around it by having the OS duplicate the handle (using dup() or a similar system call). So each thread owns a unique handle to the socket, and the OS deals with cleanup when the last handle to the socket disappears.

I see no reason why this wouldn't work on datagram sockets on the different platforms.

fpagliughi commented 1 year ago

You're right. Those were left out, but purely by accident. Those functions are going in now, and will be part of the next release.

fpagliughi commented 1 year ago

In new Release v0.8.1