The C language offers several possibilities and the use of different functions for sending and receiving the data over a socket. Each of them provides a different property or constraint. However, the “socket.h” header defines the recv() function which is specifically designed to read the socket files and provides options for receiving the mode, waiting, etc., making it most suitable for use in connections.
In this Linux Hint article, you will learn how to use the recv() function. One of the two functions are used to send and receive the data over a socket in the C language.
We will look at the syntax of this function and its theoretical description of how it works, the input and output arguments, and the data type that is accepted by each of them.
Then, we will implement what we learned in a practical example with code snippets and images where we create a console application to send the commands to the server and receive the response with the recv() function.
Syntax of the Recv() Function in C Language
Description of the Recv() Function in C Language
The recv() function receives the data that is sent through a socket. This function receives the data from the socket whose identifier is set to sockfd. The received data is stored in the buffer which is pointed to by buf whose size must be specified in the len input argument. The input flags are control flags which are grouped in an integer that configures how this function receives the data through the socket.
When recv() is called and there is no data that is waiting in the queue, the program waits until a new packet arrives and then resumes the execution of the next line of code. This dead time can be suppressed using the pool() function to query whether or not the data is waiting to be received, thus avoiding unnecessary calls to the recv() function.
Another possibility is to enable the MSG _DONTWAIT flag to set a non-blocking reception. If the recv() function returns successfully, it returns the number of bytes which are received as the result. If an error occurs on reception, recv() returns -1 and the specific code for that error can be retrieved via the errno global variable.
Next, let us look at the individual input arguments of this function in detail:
sockfd: This argument is an integer that must contain the identifier of the socket through which the data is received. This identifier is assigned by the system during socket creation and the result that is returned by the socket() function.
buf: This entry is a pointer to the buffer where recv() stores the received data. The buffer should be sized according to the size of the packets to be received. Buffers of 1025 bytes are sufficient for TCP connections.
len: This argument is of type size_t and tells the function of the size of the buf receive buffer.
flags: This integer contains a set of control flags that give the function very useful properties. The values of these flags are specified by a mask between this integer and the selected flag, applying the OR logical operation between them. The values that these flags represent and their definitions can be found in the “socket.h” header. We see each of these flags and a brief description of them in the following:
MSG_OOB = 0x01 Processes the out-of-band data.
MSG_PEEK = 0x02 Peeks at incoming messages.
MSG_CTRUNC = 0x08 Controls data lost before delivery.
MSG_PROXY = 0x10 Supplies or asks the second address.
MSG_TRUNC = 0x20 Returns the size of the received datagram. UDP only.
MSG_DONTWAIT = 0x40 Non-blocking rejection.
MSG_WAITALL = 0x100 Waits for a full request.
The recvc() function is defined in the “sys” folder in the “socket.h” header. We need to include it in our file as follows:
How to Receive Data through a Socket with the Recv() function in the C Language
In this example, we connect a socket to www.google.com, send the HTTP commands to the server, receive its response using the recv() function, and then display it in the command console.
The first part of this example is the connect_to() function.. It creates a TCP socket for the HTTP service, connects it to the “www.google.com” domain, and returns the socket_id socket identifier. Since this is all we need to show how recv() works, we will not go further into this part.
The second part is the main function where, with the socket connected, we send the command to the server with the send() function and then get the response in the buf buffer with the recv() function.
You can see the “main” code for this application and an explanation of each step shown in it in the following illustration:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
int connect_to ();
int main (){
int socket_id;
char buffer[1025];
//Step 2
socket_id = connect_to();
//Step 3
while (1){
printf("Send http command. To exit press Ctrl+c \n");
fgets(buffer, 1025, stdin);
send(socket_id, buffer, 1025, 0);
memset(&buffer, '\0', 1025);
//Step 4
recv(socket_id, buffer, 1025, 0);
//Step 5
printf("%s\n", buffer);
memset(&buffer, '\0', 1025);
}
}//End main
Step 1: Here, we add the required headers, create the main function, and define the socket_id integer which is the socket identifier and the 1025-element buffer[] character array where the send() and recv() functions store the data that they send and receive from the server.
Step 2: After the variables are defined, we call the connect_to() function and pass the socket_id identifier as the output argument. The function returns with a connected socket and its identifier in socket_id.
Step 3: With the socket and its handle being connected, we create a while(1) loop in which the fgets() function waits for the user to enter an HTTP command at the command console.
When you enter the command, it is sent to the server through the socket which is identified by socket_id using the send() function.
Step 4: Call the recv() function to get the server’s response. When calling the recv() function, we send the socket identifier, socket_id, as the first input argument. As the second and third arguments, we send the buffer[] buffer pointer and its size in bytes in which case we set the size of the packets to 1025. In this case, we set the flags entry to 0.
Step 5: The recv() function returns when it finishes receiving the packet. The received data from the server is displayed on the command console by printing the buffer[] contents with the printf() function. The memset() function is used to clear the buffer after it is used by the send() and recv() functions.
Next, we see the main code and the connect_to() function.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
int connect_to ();
int main ()
{
int socket_id;
char buffer[1025];
//Step 2
socket_id = connect_to();
//Step 3
while (1){
printf("Send http command. To exit press Ctrl+c \n");
fgets(buffer, 1025, stdin);
send(socket_id, buffer, 1025, 0);
memset(&buffer, '\0', 1025);
//Step 4
recv(socket_id, buffer, 1025, 0);
//Step 5
printf("%s\n", buffer);
memset(&buffer, '\0', 1025);
}
}//End main
/***************************************************************/
/* connect_to function*/
int connect_to (){
int port = 80;
int error;
int socket_id;
char buffer [1025];
struct hostent *server;
struct sockaddr_in client;
memset(&server, 0, sizeof(server));
server = gethostbyname ( "www.google.com" );
if(server == NULL)
{
printf("\nError getting domain data.\n");
return 1;
}
socket_id = socket ( AF_INET, SOCK_STREAM, 0 );
client.sin_family = AF_INET;
client.sin_port = htons(port);
bcopy((char *) server->h_addr,
(char *) &client.sin_addr.s_addr,
sizeof(server->h_length));
error=connect(socket_id, (struct sockaddr *) &client, sizeof(client));
if (error < 0){
printf ("\nCould not establish connection to the server\n");
close( socket_id);
return 1;
}
printf ("\nConnect to : %s\n", inet_ntoa( client.sin_addr ));
return socket_id;
}
Create a file named “example.c” and save it in “Documents”. Copy the code and paste it there. Save it and compile the code in GCC with the following command:
Then, run the program with the following command:
The application connects to “www.google.com” and waits for us to introduce an HTTP command.
In the following figure, we see the http GET command that is sent and the server’s response which is retrieved by the recv() function in buffer[].
How to Identify the Errors that the Recv() Function Can Generate in C Language
The errors that can occur when using the recv() function are varied, ranging from network errors to incorrect buffer sizes. The definitions of these codes and their numerical representation can be found in the “errno.h” header in “asm-generic” folder and can be retrieved by accessing the errno integer.
With the following snippet in step 4 of the previous code, we call the recv() function from an if condition. When an error occurs, a message is printed followed by the predefined number which identifies the error that is stored in the errno integer:
if ( recv(socket_id, buffer, 1025, 0 ) < 0)
printf ( "Error :%i", errno );
The following are the definitions of the errors that can be generated by the recv() function and a brief description of each error:
The following figure shows the error that occurs when trying to receive the data via a non-existent socket identifier. The resulting error in errno is equal to 88 “Socket operation on non-socket”.
Conclusion
In this Linux Hint article, we explained how to use the recv() function to receive the data over a socket. We looked at the syntax of this function as well as a description of how it works, the input and output arguments, and the data types they accept.
To see how this function works, we created a console application in which we used the recv() function to receive the response from a server through a socket which is connected to it. We also showed you how to identify and classify some of the most common errors when using this function.
We hope that you found this article useful. For more articles about the C language and Linux tips, use the search engine on our website.