I have to agree, Winsock doesn't such so much as a lot of people suck at using it. I don't mean to disparage anyone here with that comment.
It's amazing how many VERY POOR samples and tutorials are out there on using Winsock (or for that matter TCP/UDP programming through any API). My "favorite" goof is all of the code samples that assume TCP works like disk record I/O or something.
These kindergarten Winsock examples make the assumption that when one end does a SendData the other end can do a GetData and it's all good. This works in simple, degenerate cases. The problem is that the data sent in a SendData doesn't have to go out immediately to the other end, Nagling and other factors can mean that several SendData's in a row can all show up in one GetData at the other end. Or one SendData's data may take two or more GetDatas to pick it all up.
As for getting through a firewall goes, we're probably really talking about the typical residential NAT router, right?
Well you have two problems. One is getting an inbound port opened, and the other is getting the router to forward the port to the right private-addressed client inside the router.
Most simple IM systems deal with this simply: they aren't peer-to-peer. Every client connects to a central server at a fixed public IP address on an open port and all data is exchanged through there. More advanced systems expect you to open a range of ports to all comers and map them to one client system inside the router, while others rely on UPnP techniques to open and map ports on demand. The latter requires a UPnP router of course.
You might look at
http://alumnus.caltech.edu/~dank/peer-nat.html. Try Google for
"peer-to-peer" router or
"peer-to-peer" NAT too.