Sending and Receiving Data
This section covers the fundamental functions and concepts related to sending and receiving data over a network using the Windows Sockets API (Winsock). Efficiently managing data flow is crucial for building robust network applications.
Core Functions for Data Transfer
Winsock provides a set of functions to send and receive data. The choice of function often depends on whether the socket is connection-oriented (like TCP) or connectionless (like UDP).
Connection-Oriented Sockets (e.g., TCP)
send()
: Transmits data on a connected socket. It attempts to send the entire buffer but may send fewer bytes than requested.int send( _In_ SOCKET s, _In_reads_(len) const char *buf, _In_ int len, _In_ int flags );
recv()
: Receives data on a connected socket. It attempts to receive data into the buffer but may receive fewer bytes than requested.int recv( _In_ SOCKET s, _Out_writes_to_(len, return) char *buf, _In_ int len, _In_ int flags );
sendto()
: Sends data to a specific destination address. This function is typically used with connectionless sockets but can be used with connected sockets as well.int sendto( _In_ SOCKET s, _In_reads_(len) const char *buf, _In_ int len, _In_ int flags, _In_reads_bytes_(tolen) const struct sockaddr *to, _In_ int tolen );
recvfrom()
: Receives data from a socket and retrieves the source address of the sender. This is the primary function for receiving data on connectionless sockets.int recvfrom( _In_ SOCKET s, _Out_writes_to_(len, return) char *buf, _In_ int len, _In_ int flags, _Out_writes_bytes_opt_(*fromlen) struct sockaddr *from, _Out_opt_ int *fromlen );
Connectionless Sockets (e.g., UDP)
While sendto()
and recvfrom()
are the primary functions for connectionless sockets, you can also establish a connection using connect()
on a UDP socket. If a connection is established, you can then use send()
and recv()
, though this is less common for UDP.
Understanding Flags
The flags
parameter in these functions can modify their behavior. Common flags include:
MSG_PEEK
: Inspects incoming data without removing it from the receive queue. The nextrecv()
orrecvfrom()
call will still retrieve the same data.MSG_DONTROUTE
: Bypasses the normal routing process and sends the datagram directly to the network interface.MSG_OOB
: Sends or receives out-of-band data.
Data Buffering and Size
When sending or receiving data, it's essential to manage buffer sizes carefully. Winsock functions return the number of bytes actually sent or received. For connection-oriented sockets, you might need to loop to ensure that the entire desired amount of data is sent or received:
int totalBytesSent = 0;
while (totalBytesSent < desiredSize) {
int bytesSent = send(socket, buffer + totalBytesSent, desiredSize - totalBytesSent, 0);
if (bytesSent == SOCKET_ERROR) {
// Handle error
break;
}
totalBytesSent += bytesSent;
}
Similarly, for receiving, you should be prepared to call recv()
multiple times until all expected data has arrived.
Error Handling
Always check the return value of Winsock functions. A return value of SOCKET_ERROR
indicates that an error occurred. You can retrieve detailed error information using WSAGetLastError()
.
Related Functions
socket()
: Creates a socket.connect()
: Establishes a connection to a remote host.bind()
: Associates a local address with a socket.WSAGetLastError()
: Retrieves the error code for the last Winsock operation.