Problem using Connect(), send(), recv, with UDP sockets - c++

For my Uni assignment I have to create a fast action paced networked game and so have chosen to use UDP as opposed to TCP. I am aware of a lot of the differences in programming both UDP and TCP and have read through most of the relevant parts of MSDN's documentation on winsock. On MSDN it states that creating a UDP socket via the connect() function should bind the socket to the address and port specified and as a result be able use the send() and recv() functions with the created socket.
For my application I create a client and use connect() using the loopback address which sends a number of packets via the send() function. The client, after calling select(), then receives the packets it sent out. However the result I get from the recv() function is SOCKET_ERROR and the error description using WSAGetLastError() is "An existing connection was forcibly closed by the remote host".
If i use the bind() function and use sendto() to send data over the loopback address, I recv() packets without any errors... Does anyone know why the connect() function is not doing what it is supposed to do, and has anyone been able to use UDP sockets with the connect() function?

You will need to call bind() if you want your program to receive UDP packets. connect() only sets the address that the socket will send packets to if you call send(); it does not associate the socket with a local UDP port to receive on; for that you must call bind().

"UNIX Network Programming" points out that a connect call made on a UDP client side socket figures out and stores all the state about the destination socket address in advance (masking, selecting interface, etc.), saving the cost of doing so on every ::sendto call. This book claims that ::send vs ::sendto can be up to 3x faster because of this reduced overhead - data can go straight to the NIC driver bypassing most IP stack processing. High performance game programmer's may want to consider this.

you should check Beej's Guide to Network Programming Using Internet Sockets, there are nice examples that address your question.

Keep in mind that the UDP protocol is a "connectionless" protocol meaning that you never ever connect to the host, you just send out data. So you can see that connect as an action is meaningless for UDP.
For UDP you should use sendto() and recvfrom() in these function you specify the address and the buffers and that's about it, everything else that is comfortably handled for you in TCP is gone you have to handle things on your own.
In the MSDN documentation its mentioned that you can in fact somehow use the normal send/recv functions with UDP but why would you when you have separate functions already? Like other commented already connect() for UDP does something else it's not essentially a "connect" operation but a sort of a filter to set up send()/recv() for UDP usage.

Related

Connect a UDP socket, but still receive datagrams from other sources

Is it possible to set the default destination of a UDP socket just like connect does, but without loosing the ability to receive datagrams from other sources?
I'm talking about the native OS socket API (BSD-socket / winsock2) and I'm interested in answers for both linux and windows platforms.
[EDIT:]
In case this is unclear, here is the problematic part from the connect docs:
If the socket sockfd is of type SOCK_DGRAM then addr is the address to which datagrams are sent by default, and the only address from which datagrams are received.
Is it possible to set the default destination of a UDP socket just
like connect does, but without loosing the ability to receive packages from other sources?
As far as I can tell, it is not -- connect() on a UDP socket both sets a default-send-destination and installs a filter so that incoming UDP packets from all other destinations than the specified address/port are dropped.
My solution to the problem was to just call sendto() and recvfrom() instead (if you have a UDPSocket class or similar in your codebase, you can cache the default-send address as a private member variable in that class, so that the rest of your codebase can just call a Send() method, and leave it to that method to handle the sendto() arguments)

C++ UDP RecvFrom, SendTo Different Sockets

i wrote a multithreaded UDP server after the following scheme:
Scheme:
1 Receiver Thread
(Multiple Worker Threads, each has an own Socket, not bindend ,just created Ipv4, UDP,Datagram)
Message gets pushed to 1 worker which then proceed's it and then sends an answere with its own socket.
Problem:
This works perfectly on all my own test programs but for some odd reason it doesnt work with an old software for what i am emulating the server. The software uses async Wsa (overlapped), but i still doesn't get why it doesnt work.
Confusion:
It works if I use the same socket for sending as i used for receiving the data on the serverside. I dont get why, udp is a connectionless protocol so how can it detect a different socket?
Confusion: It works if I use the same socket for sending as i used for
receiving the data on the serverside. I dont get why, udp is a
connectionless protocol so how can it detect a different socket?
If you look in the UDP headers of the packets you are sending you will notice that they contain a "UDP Source Port" field. That field can be examined by the receiver of the packet (via recvfrom()) to find out which UDP port the sending UDP socket used on the sending machine (note that this is different from the "UDP Destination Port" field that determines which port the packet should be delivered to on the receiving machine). It's possible that in your case, the program you are communicating with is looking at that field and adjusting its behavior based on that field's value.
If you're wondering what that field will be set to if you never called bind() on the sending UDP socket, the answer is that the OS will choose an available UDP port number to send from (essentially an implicit bind()).

Winsock ~ Creating an UDP Listener (Multiple vs 1 socket)

Dear Stackoverflowers,
I am researching networking a bit and I decided I'd like to create a small and simple networking library with Winsock. (I am using Completion Ports and Overlapped IO though)
As I researched a bit I came to the following steps for a TCP Listener(Correct me if I am wrong):
Create a Listening Socket
Bind it to a port/IP
Listen on it
When a new connection is created, give a seperate Socket for that connection.
Listener continue's to listen, the specific connection is handled as needed.
EDIT: With a 'connection' from here I mean communication between the server and distinct clients.
Though for an UDP Listener we need to make use of WSARecvFrom which returns the IP address at the lpFrom parameter. Now I was wondering the following:
Is it better to make one UDP Socket listen to incoming connections on a specific port with WSARecvFrom and create new sockets for every specific connection? Or could I just use the UDP Socket itself with WSASendTo. Would that cause any performance penalties if one UDP Socket is used for for example 1000 connections? Or would it be the same or even better then creating/duplicating seperate Sockets for each different incoming connection?
Note: If multiple sockets are needed how would you handle sockets listening on the same port or could a client accept UDP from different ports?
Hope you guys can help!
Ps. Extra tips are always welcome!
Unlike TCP, UDP is connection-less, and as such you don't need to create separate sockets for each party. One UDP socket can handle everything. Bind it to a local IP/Port and call WSARecvFrom() once, and when it reports data to your IOCP you can process the data as needed (if another thread if needed) and then call WSARecvFrom() again. Each time new data arrives, you have to look at the reported lpFrom address to know the IP/Port of the sender. And yes, you can use the same UDP socket for sending data to each sender when needed.

Boost.Asio datagram (UDP) socket that is both bound and connected

I have problems understanding the concept behind Boost.Asio's (using v1.49.0) boost::asio::ip::udp::socket sockets.
First I am gonna to to explain what I want to achieve:
I hide the Boost.Asio sockets behind a very simple interface (Pure Abstract Base Class), so I have two wrapper classes that allow to access either a stream socket or a datagram socket.
I want to configure both the local endpoint and the remote endpoint before passing the Boost.Asio socket to the constructor of my wrapper class.
I want to use the socket.receive (alternatively boost::asio::read) and socket.send (alternatively boost::asio::write) member functions instead of the socket.receive_from and socket.send_to member functions.
The only way to use socket.send and socket.receive with a boost::asio::ip::udp::socket seems to connect the socket.
A UDP socket can both be bound and connected:
Binding is achieved via the socket.bind member function.
Connecting is achieved via the socket.connect member function.
The problem is, that even though I am able to
Open the socket,
Set socket options,
Bind the socket,
Connect the socket,
and to be able to send data via the socket, I can not receive data from the socket. If I don't connect the socket, I can receive data via the bound local endpoint, but I am unable to send data with the approached described.
So my central question is: Am I trying something that is impossible to achieve?
Can I only use bind or connect with one socket instance?
If the answer to the two previous questions is no: What do I have to do, to be able to receive and send data via a bound and connected Boost.Asio UDP socket.
I know that UDP is in fact connectionless, therefore the text uses Boost.Asio terminology. I have also read connect on "connection less" boost::asio::ip::udp::socket which seems to indicate that it is impossible what I am trying.
You are missing one point from man page ofconnect:
If the socket sockfd is of type SOCK_DGRAM, then addr is the address to which datagrams are sent by default, and the only address from which datagrams are received.
This means, that if you want to connect the socket, then it will be able to receive datagrams only from remote endpoint (the connected one), i.e. peer will have to bind own socket before sending datagram to your socket waiting for data.
If you need to received data from more than one peer, you can connect udp socket to "any" address (i.e. 0.0.0.0 - udp::v4()) and some port.

UDP Hole Punching (c++/winsock)

stackoverflow users!
I have an app that has to deal with p2p, and that's how I get to UDP Hole punching. But I ran into troubles with implementation. Hope, you can give me some tips.
I've got server, which works perfect and introduces clients to eachother, but clients can't connect probably because of my small exp working with sockets. So, client algo is:
Create udp socket (socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);)
Send message to server via sendto function
Use recvfrom locker function to get an answer from server
After those 3 steps I get peer endpoint. Next, I was trying to connect clients in two ways:
Way1:
Use the same socket to send data to peer via sendto function, but passing another sockaddr
Listen with recvfrom locker function (And at that point I'm getting WSAECONNRESET error)
Way2:
Create new socket
Bind it
Use it to send data to peer
Listen
In that way one client fails on binding and another fails on listening with errors WSAEADDRINUSE and WSAECONNRESET. I'm obviously doing something wrong and your help would be highly appreciated. Thanks in advance.
P.S. Wanna share a good article about UDP Hole Punching in order to help those, who is new to this technique: http://www.brynosaurus.com/pub/net/p2pnat/
If you read the documentation for recvfrom(), it says:
WSAECONNRESET
The virtual circuit was reset by the remote side executing a hard or abortive close. The application should close the socket; it is no longer usable. On a UDP-datagram socket this error indicates a previous send operation resulted in an ICMP Port Unreachable message.
Which means your call to sendto() is failing. That makes sense if one or both clients are behind a router. Based on your description (and lack of code), you are not actually performing any hole punching to open up the router(s) to allow client-to-client packets to pass through. You have only sent a message to your server, which allows for client-to-server and server-to-client packets to pass through. A few more packet exchanges between each client and the server are required to perform the hole punching on each end, as described in detail in the article you linked to. Are you actually doing what the article says to do?