0
votes

Here is a sample socket programming snippet from the client side. My question revolves around the type-casting that casted sockaddr_in into sockaddr. My question is that why is that casting necessary there, what is going on there exactly?

#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#define PORT 8080
int main ( int argument, char const *argv[] )
{
int obj_socket = 0, reader;
struct sockaddr_in serv_addr;
char *message = "A message from Client !";
char buffer[1024] = {0};
if (( obj_socket = socket (AF_INET, SOCK_STREAM, 0 )) < 0)
{
printf ( "Socket creation error !" );
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
if(inet_pton ( AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0)
{
printf ( "\nInvalid address ! This IP Address is not supported !\n" );
return -1;
}
if ( connect( obj_socket, (struct sockaddr *)&serv_addr, sizeof(serv_addr )) < 0) // <--- QUESTION ABOUT THIS LINE
{
Printf ( "Connection Failed : Can't establish a connection over this socket !" );
return -1;
}
send ( obj_socket , message , strlen(message) , 0 );
printf ( "\nClient : Message has been sent !\n" );
reader = read ( obj_socket, buffer, 1024 );
printf ( "%s\n",buffer );
return 0;
}

I've been reading the documentation and going throughout the header files to understand the structures however there is one last thing that I couldn't get.

The <sys/socket.h> header defines the sockaddr structure that includes at least the following members: sa_family_t sa_family address family char sa_data[] socket address (variable-length data)

The <netinet/in.h> header shall define the sockaddr_in structure, which shall include at least the following members: sa_family_t sin_family AF_INET. in_port_t sin_port Port number. struct in_addr sin_addr IP address.

My question is, at this line of the code:

if ( connect( obj_socket, (struct sockaddr *)&serv_addr, sizeof(serv_addr )) < 0)

What is the purpose of this casting here which casted sockaddr_in to sockaddr. I understand that it is mandatory to cast here, but I would like to know why is it so? Thank you

1
The socket API is ancient and written in/for C. So, you will find some API decisions which are not anymore usual (especially not in C++). - Scheff's Cat
O.T.: The indentation is completely missing. I guess you're copy/pasting into a Smartphone. Additionally, I saw a Printf the compiler would probably complain about. ;-) - Scheff's Cat
I have specified the casting that I previously mentioned. I appreciate your concern. To be clear, when connnecting -- the code is casting sockaddr_in to sockaddr *. My question is why is this happening, what's the reason behind it? - Heathen
This might address some of your doubts stackoverflow.com/a/42190913/4885321 - alagner
connect requires its second argument be a struct sockaddr *. A &serv_addr is struct sockaddr_in *. The socket api was crafted for passing in generic addresses and letting the socket configuration and address header info (which is in a sockaddr), along with the rest of the data known because of the third argument (the size). In short, it's the most dumbed-down non-inheritance-but-acts-like-it system you're apt to ever see, and casting is required, lest your compiler tell you the type is wrong. - WhozCraig

1 Answers

0
votes

What is the purpose of this casting here which casted sockaddr_in to sockaddr.

sockaddr_in is not casted to sockaddr. sockaddr_in* is casted to sockaddr*.

That cast is done because the function connect which is being called doesn't accept a sockaddr_in* parameter, but a sockaddr*.


P.S. I recommend to not manually create a sockaddr_in, but instead to use getaddrinfo to create it.

P.P.S char *message = "A message from Client !"; is ill-formed in C++. The code that you've posted seems to be C rather than C++.