I write this as a separate answer, since the details are completely different from the one I wrote earlier.
So, based on Kalmi's comment about the session ID, I wondered why I can open two ping programs on the same machine, and the answers do not intersect. They are both ICMP, so both use ports without ports. That means something in the IP stack, you need to know what socket these answers are for. For ping, it turns out that the identifier used in the ICMP packet data is part of ECHO REQUEST and ECHO REPLY.
Then I looked at this wikipedia comment about ICMP :
Although ICMP messages are contained in standard IP datagrams, ICMP messages are usually treated as a special case, different from regular IP processing, and not processed as a regular IP sub-protocol. In many cases, you need to check the contents of the ICMP message and deliver the appropriate error message to the application that generated the original IP packet, which prompted the ICMP message to be sent.
which was developed (indirectly) here :
Internet header plus the first 64 bits of raw datagram data. This data is used by the host to match the message to the appropriate process. If a higher-level protocol uses port numbers, they are supposed to be in the first 64 bits of the data source datagram data.
Since you are using UDP, which uses ports, it is possible that the network stack redirects the ICMP message back to the original socket. This is why your new and separate socket never receives these messages. I assume UDP is eating an ICMP message.
If I'm right, one solution to this is to open a raw socket and manually create your UDP packets, listen to everything that comes back, and process UDP and ICMP messages, if necessary. I’m not sure what this would look like in the code, but I don’t think it would be too complicated and could be considered more “elegant” than the winpcap solution.
Also, this link, http://www.networksorcery.com/enp/default1003.htm , seems like a great resource for low-level network protocols.
Hope this helps.