Hi Martin,
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.
Infinite retries will not occur if a timeout is set for the [tcpserver] to decide that the other end has crashed. This timer will not wait and block, but increment occasionally. The person programming the patch can wait for output of the object to confirm that the previous transfer has completed if it is of his concern.
Yes, the data WILL be blocked in the sense that it is being buffered in the object, but without causing a pause in the process. (Whether setting the socket to non-block or using "select" with a timeout of zero was not my concern)
Users will also benefit from, while having to pay attention to broken connections, can be less concerned about how to resend failed packets over a socket that is not broken but simply delayed.
...Doesn't allowing this sort of usage make your objects more compatible with the previous design?
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.
Having said all of the above, this point was my main concern.
With your new design, does the OS also flush data a byte at a time over the network, or does it buffer it for a reasonable duration?
The earlier sounds like to introduce massive overhead caused by TCP headers, especially when we are speak of sending amounts of data that may flood the socket's "send buffer." In the later case, the OS may indicate that bytes entered the socket, while they were actually only buffered while the connection breaks and was never sent.
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?'
I agree with you on this point.
All mentioned out of curiosity.. I don't know enough on writing externals to implement what I suggested myself, and do truly feel respect for your work.
Perhaps I should just pull out a packet analyzer and confirm what goes on myself before nagging about it.
-- David Shimamoto