smoltcp-rs / smoltcp

a smol tcp/ip stack
BSD Zero Clause License
3.64k stars 404 forks source link

Can multiple tcp sockets listening on the same endpoint of one interface? #852

Closed StevenJiang1110 closed 8 months ago

StevenJiang1110 commented 8 months ago

In linux, the listen syscall can accept a backlog parameter, so it can accept multiple connection request meantime.

Since the listen method in smoltcp does not has a backlog paramter now, I wonder if I can construct multiple socket listening on the same address to mimic the backlog behavior.

I have tried it but the second connection will reports error that ACK cannot be accepted. So is it impossible by design? or is it only my programming mistake?

Dirbaio commented 8 months ago

There's no equivalent of linux "backlog", each socket can accept only 1 connection. If you want to accept multiple, create N sockets, call listen() on them on the same port -- it's fine to have N listening sockets on the same port, incoming connections go to a random one.

StevenJiang1110 commented 8 months ago

Thanks a lot. The problem is solved.

lz1998 commented 7 months ago

There's no equivalent of linux "backlog", each socket can accept only 1 connection. If you want to accept multiple, create N sockets, call listen() on them on the same port -- it's fine to have N listening sockets on the same port, incoming connections go to a random one.

Is there something help me to manage the sockets with const generics N(max connections), RB(read buffer size), WB(write buffer size)?

use embassy_net::driver::Driver;
use embassy_net::Stack;
use embassy_net::tcp::TcpSocket;

pub struct TcpListener<'a, const N: usize, const RB: usize, const WB: usize> {
    inner: [(TcpSocket<'a>, [u8; RB], [u8; WB]); N],
}

pub struct TcpStreamGuard {}

impl Drop for TcpStreamGuard {
    fn drop(&mut self) {
        // put back
        todo!()
    }
}

impl<'a, const N: usize, const RB: usize, const WB: usize> TcpListener<'a, N, RB, WB> {
    pub fn new<D: Driver>(stack: &'a Stack<D>) -> Self {
        let inner = [(); N].map(|()| {
            let mut r_buffer = [0; RB];
            let mut w_buffer = [0; WB];
            let inner = TcpSocket::new(stack, &mut r_buffer, &mut w_buffer);
            (inner, r_buffer, w_buffer)
        });
        Self {
            inner,
        }
    }

    pub async fn accept(&self) -> TcpStreamGuard {
        todo!()
    }
}