1
votes

Network programming noob here,

I'm confused by behavior of accept and connect socket functions. In most programming languages, wrappers of those functions return different types of values: accept returns a new descriptor that we can use to send/receive data, but connect returns nothing(or returns an error code).

To me it looks like connect should also return a descriptor. They both open a channel between two sockets, but only one of the functions return something useful to communicate with the remote socket.

This effects the way I structure my program. For example, I can easily spawn a new worker/thread/etc. for every incoming connection, but it's not easily possible for every connections that I create using connect, because I don't have a new descriptor in this case.(so I can't use recv and send without doing some bookkeeping)

Can anyone explain me why is this working this way?

I think the reason is that because socket wrappers in programming languages follow the BSD API closely and in this case my question is: Why BSD sockets work this way? Current implementation leads to unnecessarily complex programs or redundant sockets. I either need to do more bookkeping(leads to more complex programs) or create a new socket for every out-going connection(leads to redundant sockets).

Thanks.

1

1 Answers

2
votes

connect() takes an existing descriptor as input. You create and configure the descriptor first and then connect() it to the server. So there is no need for it to return a new descriptor since you have to create the descriptor beforehand.

accept() also takes an existing descriptor as input, however that descriptor represents the listening socket. When a client is accepted, a unique descriptor is needed for reading/writing with that particular client, the listening descriptor cannot be used for that, so accept() returns a new descriptor.

You don't need to structure your thread differently. On the client side, after you connect() to the server, spawn a thread and give it the descriptor that was connected. On the server side, after you accept() a client, spawn a thread and give it the descriptor that was accepted. In both cases, the thread only has to care about which descriptor to operate on, not where that descriptor came from. Both threads can use recv() and send() as needed, and then close() the descriptor when done using it.

You cannot reuse a socket descriptor for a new connection (well, WinSock2 on Windows has non-standard extensions to allow that, but that feature is not commonly used). Once a connection is disconnected, its descriptors must be closed. You have to create new descriptors whenever you need to create a new connection.