Reputation: 2209
I have a sender that TCP-connects, sends block of data, and closes the socket. I'd like to write the simplest, but reliable program that does the above. The first thing comes into mind (e.g. in .NET, although the question relevant to sockets in general):
// assuming LingerOption(false), NoDelay set to whatever
var client = new TcpClient().Connect(server, port);
var stream = client.GetStream();
stream.Write(data, 0, data.Length);
stream.Close();
client.Close();
Now to some questions basing on reading of various MSDN and other materials:
Upvotes: 4
Views: 4019
Reputation: 11446
TcpClient.Close
says "The Close method marks the instance as disposed and requests that the associated Socket close the TCP connection. Based on the LingerState property, the TCP connection may stay open for some time after the Close
method is called when data remains to be sent. There is no notification provided when the underlying connection has completed closing."
In short, unless you've fiddled with the LingerState, calling Close
will not discard the OS buffer of the data - the TCP stack will try its best to deliver the data you've Written.
Be sure to catch exceptions though, any of your Write
or the 2 Close
calls might throw an exception if things went bad - and make sure you dispose the socket and stream in those cases.
Note also that the Write()
call might not block until the data is sent, it'll only block until the data is copied to the TCP stack (and depeding on too many things, TCP might partially send some of that data out on the network before Write
returns)
Upvotes: 1
Reputation: 2209
It's is absolutelly OK to call Close just after Socket.Write. Here's what TCP RFC 793 says:
"Closing connections is intended to be a graceful operation in the sense that outstanding SENDs will be transmitted (and retransmitted), as flow control permits, until all have been serviced. Thus, it should be acceptable to make several SEND calls, followed by a CLOSE, and expect all the data to be sent to the destination."
The confusion, in part, comes from MSDN documentation:
"If you are using a connection-oriented protocol, Send will block until all of the bytes in the buffer are sent"
In reality, blocking Write only copies data to outgoing buffer and returns. It's the network provider responsibility, under RFC 793, to complete the delivery of the data after Socket.Close is called (as long as the connection is not dead, of course).
Upvotes: 4
Reputation: 445
This is sidestepping your original question, but you didn't say what kind of data you were sending. Why did you decide to use a TCP connection in the first place? How often are you writing these blocks of data? If it's very often, I would recommend one of two things:
1) Keep the TCP.Stream open. Otherwise, you could exhaust the TCP stack of available source ports (1025-65535) if you send more than ~64000 blocks in less than 4 minutes. This would get worse if there are other applications open on the source machine. Once this happens your application will hang or error until the first port older than 4 minutes becomes available.
2) Use UDP instead of TCP. There is no guarantee of delivery, but if this is real-time data, then you don't want to use TCP as it could significantly delay real time data.
If you are using TCP, the Client.Close() should send a FIN over the TCP stack, and unless the other host has crashed or the network between them has gone down, should guarantee delivery.
Whether you use TCP or UDP if you are concerned about every block of data arriving at its destination, you should build some application level checking that all blocks arrived in order and uncorrupted...
Upvotes: 0
Reputation: 2412
if the receiver is not reached to Read, you may lose some part of data and this depends on size of buffers used in lower layers.
But If the receiver is blocked on Read, so there is no problem while you provide enough buffer when Reading.
Assuming a reliable network and executing "Read" before "Write" and enough buffer at receiver side, this code is absolutely reliable!
But the solution!:
As i said size of the buffer in receiver side really matters. if the buffer doesn't have enough space, you will lose by this code!
So you have three choices:
TransmitFile
function in Win32 API for transmitting files)If you know maximum size of data, then i offer you 1 Else If you don't have enough time and not interested in protocols , then i offer you 2 Else i offer you 3
Good luck ;)
Upvotes: 1
Reputation:
The receiver could send wait or retransmit messages to the sender. This could happen if the receiver's recv buffers are full before the entire block of data is received, or if there are lost packets on the network. So if you quit the client before all the data is exchanged, you lose data.
Take a look at this book for your general solution: UNIX Network Programming Volume One by W. Richard Stevens.
Yes it is UNIX, but it is ultimately dealing with TCP/IP comms and that is at the root of the above. And sorry, it is not really simple, but it's also not really hard either. It's a state machine with more states than your proposal contains.
Upvotes: 1