PSPunch wrote:
From my understanding, the alternative to using multiple threads/processes would be to set the socket to "non-blocking" and implement a Pd object that buffers the messages requested to be sent. Then attempts to retry sending what the OS once rejected should be made.
It seems like that would always end up blocking something, depending on the reason for the inability to send the messages. If the other end has crashed the object would be trying sending for hours and its buffer would expand to fill up all available memory. The way I do it now in [tcpserver] is to send the messages one byte at a time, first using a select() call to verify that each byte can be sent without blocking. This is similar to using non-blocking sockets but doesn't involve timers.
This will also involve giving the object a timer to call it a fault and close the socket if no bytes seemed to have traveled over a certain period of time.
This can be done in the patch, so the user can decide what to do about unsendable messages. They can implement a timer and know what state it was in.
This probably calls for some decision making in the design of the Pd object, such as how frequently to retry sending the bytes to the socket. I was thinking a [bang] may be flexible. Whether it be triggered by [metro] or [bang~], the one designing the patch would have the most control over how to deal with the results of the transfer.
Yes, you can do all that in the patch that uses [tcpserver]. I don't think the object itself needs to be overly complex. In my experience, 'user-friendly' usually means 'opaque', 'inscrutable', 'why TF is it doing that?'
Martin