Back in VB3 days I used Catalyst SocketWrench Freeware Edition to play with TCP/IP because we had no MS Winsock control (at least in VB3 Editions that I had access to).
Recently I wanted to play with UDP Broadcasts and deal with the problem of the one client per machine limitation ("address in use" errors).
The Winsock control works great for a lot of things, but you can't set the SO_REUSEADDR option with it. This option must be set before calling .Bind(), but with the Winsock control the exposed socket handle isn't valid until after .Bind() is called.
I looked through a couple of the hacked up "Winsock control replacement in VB6" projects and sort of threw up. Not only don't they do what I need they are full of crusty coding and laughable errors. They might not be too buggy to work in simple test projects but typically their error reporting is horribly flawed.
I decided to dig around, and found that I still had SocketWrench 6.0 Freeware gathering dust in my Downloads Archive folder.
Installed that, and tried to retrofit a demo program using the Winsock control. Had a lot of small but tenacious problems because the documentation is lacking in this area but I did get it working.
I can now use UDP Broadcasts as a viable "push notification" mechanism on the LAN even with multiple programs on the same PC using it.
I didn't find very much here on using SocketWrench so perhaps it was never that popular after VB5 came out.
Does anyone else here still use it? I see a lot of whinging about the Winsock control (most of it coming down to misuse), but you can still find the SocketWrench 6.0 Freeware Edition to download if you do a few searches.
Here's my quick and dirty demo, a simple program using a PTT UserControl ("push to talk") that wraps an instance of SocketWrench.
The main value in this is pushing notifications between application instances for things like "I updated the database, you might want to refresh any views of the data you are holding."
This demo is interactive with the users but that's just to show it is working. PTT is more of a "program's walkie-talkie" not something for building Yet Another Chat System.
I would have posted this earlier but it isn't of much value unless you have SocketWrench 6.0 already.
At least it's small.
Last edited by dilettante; Oct 9th, 2020 at 03:58 PM.
Reason: reposted with changes
Here's my quick and dirty demo, a simple program using a PTT UserControl ("push to talk") that wraps an instance of SocketWrench.
The main value in this is pushing notifications between application instances for things like "I updated the database, you might want to refresh any views of the data you are holding."
This demo is interactive with the users but that's just to show it is working. PTT is more of a "program's walkie-talkie" not something for building Yet Another Chat System.
I would have posted this earlier but it isn't of much value unless you have SocketWrench 6.0 already.
At least it's small.
It sounds good, but where can I download it SocketWrench 6.0
1. The machine can be multi-homed i.e. several LAN card with each card having several IP addresses
2. The local network segment can be subnetted
Originally Posted by internet
What Is Subnetting?
Subnetting is the process of stealing bits from the HOST part of an IP address in order to divide the larger network into smaller sub-networks called subnets. After subnetting, we end up with NETWORK SUBNET HOST fields. We always reserve an IP address to identify the subnet and another one to identify the broadcast subnet address.
For instance here we use 172.17.17.x/24 which is 172.17.y.x/16 subnetted with custom y = 17. In this case your BroadcastIP calculation broadcasts to 172.17.255.255 which does *not* reach 172.17.17.x listeners.
1. and 2. above are connected because the GetAdaptersAddresses API has to be used to enum all IPs + Masks as configured on the machine. (I couldn't find if pure Winsock API can provide info about configured host subnet masks.) Unfortunately VbAsyncSocket does not provide for this yet, so I'll have to tweak it before posting my port finished.
The machine can be multi-homed i.e. several LAN card with each card having several IP addresses
Of course. So what's new? This is always a problem when you play reindeer games.
PTT could have an optional property to specify the local IP address to use. If a program needed to "PTT to" multiple networks multiple instances of PTT could be used and the program can try to relay traffic among them.
If you are in this deep simple UDP broadcasts will not meet your requirements anyway. Game over, thanks for playing. Go learn about MSMQ Multicast, RabbitMQ, etc.
Originally Posted by wqweto
The local network segment can be subnetted
Granted, this is once again a real scenario.
PTT made only a minimal effort to compensate for this by providing an optional SubnetMask property to override classful network calculations in scenarios like classless networking. This one is already there, unlike a manual LocalIP property.
But again, this is more of an enterprise issue rather than a SOHO LAN issue where people don't normally have to game the system to squeeze more out of the limited IPv4 address space.
I agree these are not mere "nits" being picked. They are legitimate issues. But it's a bit like complaining that a Toyota Corolla can't pull a semi trailer or operate under water. You're expecting a lot out of a small demo program.
This is a SOHO-scale solution for serverless local push notification rather than an enterprise alternative to something server-based like message queuing.
I think a bigger issue is the lack of guaranteed delivery using UDP, and even more so UDP broadcasts. See "Perfect is the enemy of good"
No, a fast-food burger is not a fine steak prepared by a chef.
If you do have solutions to these issues with subnet broadcasts I'd love to see them.
Will an Ethernet switch even pass broadcasts between subnets? Routers are prohibited from doing so. The last thing you want is broadcast storms choking the network.
Of course. So what's new? This is always a problem when you play reindeer games.
The trouble is a lot of people have some sort of supervisor nowadays like Hyper V, VirtualBox, etc. which do bring "multi-homedness" behind the scenes like this
If you wanted something like this to push notifications about stuff like database updates you'd probably also want to limit the refresh frequency. For that you'd probably want to pick a time server machine and add a timestamp field to the message format.
Then receivers could cache that timestamp and ignore future notifications until one arrives with a timestamp "later than n seconds" after the cached timestamp. By using an authoritative time server (could be your database server) worries about clock synchronization go away.
That may be extreme overkill for a 5 user application but once you have 25, 30, 50, 80... users you don't want refreshes triggered so often.
It might even be easier to just start a one-shot Timer when an "data updated" notification arrives, ignoring any additional notifications until the Timer fires and you do a refresh.
All of that begs the question of what to do when you decide to refresh: you don't want to zap the user's work in progress. But that's probably a discussion for the Database forum. I see a lot of programs that don't even deal with update collisions that occur as it is (without notifications and view refreshes). This just adds to the complexity of any clients that can update/insert/delete.
Btw, while porting this I decided to broadcast on *all* subnets as returned by GetAdaptersInfo, not only the default LocalAddress as returned by winsock and uncovered another problem with the current protocol on this line
ByteCount = .Read(Msg, BufferSize)
. . . in Socket_OnRead event handler.
Basically what happens is that winsock might coalesce serveral datagrams if these are not .Read fast enough. So you end up with *two* (or more) messages in Msg buffer but the protocol currently does not provide for message size or message start/stop (or delimeter) and depends entirely on messages being delivered in separate datagrams. The impl just takes care for messages not to split over more than one datagram by (optimisitically) limiting message size to the (probable) network MTU.
Effectively what gets logged in the UI is someting like this
Code:
Sent: 111
Echo: 111PTT
. . . and some control character i.e. this is the second message signature leaking in the payload of the first one because Send broadcasts on multiple addresses and the 0.0.0.0 listener receives all echoes coalesced.
I wasn't expecting a high arrival rate but yes, sending via multiple networks makes the issue far more likely.
At first I was thinking "sounds like an implementation bug"
SOCK_DGRAM sockets should not be acting like SOCK_STREAM but I'm not sure they have much choice really. Since UDP has no "hold off" mechanism the only alternatives would be to drop more datagrams or rotate an expandable list of buffers.
Then some adapters:
To avoid flooding the host system with too many interrupts, packets are collected and one single interrupt is generated for multiple packets. This is called interrupt coalescing.
I hadn't even mentioned that SocketWrench is doing Unicode-to/from-ANSI on the payload data. I suppose it wouldn't hurt to use UTF-8 instead, but this was mainly meant for short notifications meaning little more than "event occurred" (e.g. "data changed"). It wasn't intended for chatting.
UDP has no congestion control and no data coalescing.
I can't reproduce your problem with the Winsock or SocketWrench controls because I have no multihomed machines. But the link above is generally considered authoritative.
Are you sure you don't have a bug? Perhaps not triggering your receive event often enough by reusing TCP logic for UDP?
I can't reproduce your problem with the Winsock or SocketWrench controls because I have no multihomed machines. But the link above is generally considered authoritative.
Are you sure you don't have a bug? Perhaps not triggering your receive event often enough by reusing TCP logic for UDP?
Just curious.
I'll test it with SocketWrench.
What happens with WSAAsyncSelect (so called hwnd message-based notifications) is something like this:
1. Datagram received by LAN card
2. Receive event fired on hwnd
3. Second datagram received by LAN card
4. Read method called in Socket_OnRead gets both messages in app's Msg buffer
5. Second receive event fired but winsock recv buffer is empty
The article linked above must be correct in sense that no two datagrams are coalesced while transmitted over the network (each in separate IP packet). It's the winsock receive buffer that makes them seem to be coalesced as these get returned by the Read method.
Wow, it works with SocketWrench -- each Read call receives *only* the datagram the Read event is in response of.
The "coalescing" in my impl was entirely self-inflicted. Winsock reported on FIONREAD that all datagrams are available in its receive buffer but these had be read by multiple calls to recv. This looping is unnecessary for UDP and after fixing it everything seems to be working as expected here. With multihomed hosts there are several *separate* echoes for each Send but this is expected as messages with the same signatures are sent on all local broadcast addresses.
Any advice on the signatures (protocol and process)? These were as compact as I could craft with the uniqueness I wanted... and still use String sends. One could always use Byte array sends of course and save a few bytes.
My "base 128" is sort of hackish but I didn't want to run afoul of ANSI mappings. Probably silly though since it seems unlikely people on a LAN would have different localization settings.