These days, networking applications utilize more than a single protocol at a time. My current server, which is a software router of sorts, needs to support TCP/IP as well as Udp channels at the same time. On top of the TCP is HTTP, but that’s already been covered.
Here I present the support for the Udp protocol. Udp differs from TCP in a few ways, key being the lack of “connection”. Every single packet is individually addressed and sent to the intended recipient. Of course you can cache the DNS lookup, so that the delivery of the packets themselves is blazing fast. There’s no redundancy, no ack, no error recovery.
When TCP/IP/UDP were first created, the error rate was probably much higher than it is today. These days, depending on the network, Udp might be a perfectly reasonable choice. The trick, from a TINN perspective, is to make programming with either protocol look relatively the same. For the most part, this just means using the same mechanism for async calls.
Here’s what the server code looks like, minus the error recovery logic:
local ffi = require("ffi"); local IOProcessor = require("IOProcessor"); local IOCPSocket = require("IOCPSocket"); -- Setup the server socket local socket, err = IOCPSocket:create(AF_INET, SOCK_DGRAM, 0); local success, err = socket:bindToPort(9090); -- Setup buffers to be used to receive data local bufflen = 1500; local buff = ffi.new("uint8_t[?]", bufflen); local from = sockaddr_in(); local fromLen = ffi.sizeof(from); -- The primary application loop local loop = function() while true do local bytesread, err = socket:receiveFrom(from, fromLen, buff, bufflen); if not bytesread then return false, err; end -- echo back to sender local bytessent, err = socket:sendTo(from, fromLen, buff, bufflen); end end run(loop);
And that’s about all there is to it. In this particular case, a single packet is received, and that packet is immediately sent back to whomever sent it. In this The receiveFrom(), and sendTo(), do in fact use IOCompletion ports, and, for a more complex server that actually does work, you might formulate this differently, utilizing multiple receive buffers, and spawning a task for each packet. But, this is the most basic form of doing Udp handling with TINN.
The socket:receiveFrom() implementation is pretty much the same as that for socket:receive(), except for the addition of the address information so you can see who sent the message, and so you can subsequently return the packet to the source.
This code is not particularly hard, and if you were programming in ‘C’, it would look pretty much the same. The key benefit though comes from the automatic semi-concurrency which is possible, without really changing the code that much. This is what makes it easier to integrate and handle.