Sending TCP and UDP Data
In the previous sections, we explained how to handle an incoming stream of data. You could say it was incoming-data driven. Sometimes you need just the opposite — you need to perform operations based on the sending of data.
Sending Data With the on_sock_data_sent Event
Suppose that in a certain system you need to send out a long string of data when a button is pressed. Simple code for that would look like this:
sub on_button_pressed
sock.setdata("This is a long string waiting to be sent. Send me already!")
sock.send
end sub
The code above would work, but only if at the moment of code execution the necessary amount of free space was available in the TX buffer (otherwise the data would get truncated). So, obviously, you need to make sure that the TX buffer has the necessary amount of free space before sending. A simple polling solution would look like this:
sub on_button_pressed
dim s as string
s = "This is a long string waiting to be sent. Send me already!"
while sock.txfree < len(s)
wend
sock.setdata(s)
sock.send
end sub
Again, this is not so good, as it would block other event handlers. So, instead of doing that, we would employ a code that uses on_sock_data_sent:
dim s as string
s = "This is a long string waiting to be sent. Send me already!"
sub on_button_pressed
sock.notifysent(sock.txbuffsize-len(s)) ' causes the on_sock_data_sent event to fire when the TX buffer has space for our string
end sub
sub on_sock_data_sent
sock.setdata(s) ' put data in TX buffer
sock.send ' start sending it.
end sub
When we press the button, on_button_pressed event is generated, so now the system knows we have a string to send. Using sock.notifysent, we make the system fire the on_sock_data_sent event when the necessary amount of free space becomes available. This event will only be fired once — and will be fired immediately if there is already enough available space.
Within the event handler for this event, we put the data in the TX buffer and start sending it.
The amount of data that will trigger on_sock_data_sent does not include uncommitted data in the TX buffer.
UDP Datagrams Are Generated as You Create Them
In Using Buffers in UDP Mode, we explained that for UDP, you have complete control over how the data you are sending is divided into the UDP datagrams. Each time you use the sock.send method, you draw the boundary between the datagrams — the previous one is "closed" and the new one "begins." You can even send out an empty UDP datagram by executing sock.send without using sock.setdata first.
Correctly Responding to the Sender of Each UDP Datagram
With UDP, your socket may be receiving UDP datagrams from several different hosts. When the on_sock_data_arrival event handler is entered (see Receiving Data in UDP mode), the following properties automatically reflect the source of the current datagram: sock.remotemac, sock.remoteip, and sock.remoteport. Additionally, the sock.bcast property will tell you whether the datagram was a regular or a broadcast one (this material has already been covered in Checking Connection Status).
Additionally, any datagram that is generated and sent from within the on_sock_data_arrival event handler is sent to the sender of the datagram that caused the event handler to be entered.
The point is that if you are sending out a datagram from within the on_sock_data_arrival event handler, you are automatically replying to the sender of the datagram being processed. The following example sends back "GOT DATAGRAM FROM xxx.xxx.xxx.xxx" string in response to any datagram received by the socket:
sub on_sock_data_arrival
sock.setdata("GOT DATAGRAM FROM " + sock.remoteip)
sock.send
end sub
For the above example, even if several hosts send datagrams to the socket at the same time, each one of these hosts will get a correct reply back!
Now consider this example: each time the button is pressed the same message is generated.
sub on_button_pressed
sock.setdata("GOT DATAGRAM FROM " + sock.remoteip)
sock.send
end sub
The difference is that when you press the button, the datagram will be sent to the sender of the most recent incoming UDP datagram that was received (and accepted) by the socket!