Winsock Core: Data Transfer
Functions for sending and receiving data over sockets.
Introduction
Efficient and reliable data transfer is the cornerstone of network communication. Winsock provides a set of functions that allow applications to send and receive data streams or datagrams across the network. These functions abstract the complexities of underlying network protocols, offering a consistent interface for developers.
Key Data Transfer Functions
Sending Data
The primary functions for sending data are send() and sendto(). The choice between them depends on whether you are working with a connection-oriented (like TCP) or connectionless (like UDP) socket.
send()
Used for sending data on connection-oriented sockets (e.g., SOCK_STREAM). The function sends a block of data through a connected socket.
int send(
SOCKET s,
const char FAR * buf,
int len,
int flags
);
s: A descriptor identifying a connected socket.buf: A pointer to the buffer containing the data to be sent.len: The number of bytes to send from the buffer.flags: Flags that control the data transmission. See Winsock documentation for details (e.g.,MSG_OOBfor out-of-band data).
sendto()
Used for sending data on connectionless sockets (e.g., SOCK_DGRAM) or when you need to specify the destination address for each send operation.
int sendto(
SOCKET s,
const char FAR * buf,
int len,
int flags,
const struct sockaddr FAR * to,
int tolen
);
s: A descriptor identifying a socket.buf: Pointer to the buffer containing the data to send.len: Number of bytes to send.flags: Transmission options.to: Pointer to asockaddrstructure containing the destination address.tolen: Size of the address structure.
Receiving Data
The primary functions for receiving data are recv() and recvfrom(). Similar to sending, the choice depends on the socket type.
recv()
Used for receiving data on connection-oriented sockets.
int recv(
SOCKET s,
char FAR * buf,
int len,
int flags
);
s: A descriptor identifying a connected socket.buf: Pointer to the buffer that will receive the incoming data.len: The maximum number of bytes to receive.flags: Flags that control the reception.
recvfrom()
Used for receiving data on connectionless sockets, and it also retrieves the address of the sender.
int recvfrom(
SOCKET s,
char FAR * buf,
int len,
int flags,
struct sockaddr FAR * from,
int FAR * fromlen
);
s: A descriptor identifying a socket.buf: Pointer to the buffer that will receive the data.len: Maximum number of bytes to receive.flags: Reception options.from: Pointer to asockaddrstructure that will receive the sender's address.fromlen: Pointer to an integer that contains the size of the address structure.
Important Considerations
- Blocking vs. Non-blocking Sockets: By default, Winsock sockets are blocking. This means that
send()andrecv()calls will wait until the operation completes. For more responsive applications, consider using non-blocking sockets or asynchronous I/O mechanisms like Overlapped I/O. - Buffer Management: Ensure your receive buffers are large enough to accommodate the expected data. If a receive operation returns fewer bytes than requested, it does not necessarily mean the sender has finished sending; more data may arrive later.
- Error Handling: Always check the return value of Winsock functions. A return value of
SOCKET_ERRORindicates an error, and you should callWSAGetLastError()to determine the specific error code. - Connection-Oriented vs. Connectionless: Understand the semantics of TCP (connection-oriented, reliable, ordered stream) versus UDP (connectionless, unreliable, unordered datagrams) and choose the appropriate socket type and functions.
WSAOVERLAPPED structure) for asynchronous data transfer.