serv_sock=socket(PF_INET, SOCK_STREAM, 0);
//...
clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_addr,&clnt_addr_size);
accept
I understand what the argument roles of the function mean. However,
I don't know what it means to have *&
in (structsockaddr*)&clnt_add
.
The signature of accept() is as follows:
int accept(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict addrlen);
The type of the second parameter addr
is structure sockaddr*
.
However, clnt_addr
you mentioned is probably structure sockaddr_in
rather than that type.
They're completely different types. Then putting the address of clnt_addr
in that function would be a no-go.
The two structures are:
struct sockaddr_in {
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
};
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
where s_family
and sa_family
are the same structures with different names, and sin_port
and sa_data
are of different types but have the same byte size.
From the sockaddr
point of view, the front of sockaddr_in
is similar to sockaddr
point of view.
In other words, sockaddr_in
is an extended form of sockaddr
.
accept()
on the BSD socket is an API that can support multiple protocols. Depending on each protocol, the representation of the address varies. New protocols may be developed and used through this API.
I want to accept different types of addresses while keeping the function named accept()
as it is possible.
However, in C language, there is no way to accept various types as the name of a function.
So, check which protocol you use through sa_family
and figure out what type of address it is. (Since the ABI in the beginning is the same, there is no problem until you determine which protocol it is.)
Return to the above method for operation, but the compiler determines that the type is different, so forcefully trick the type into accept()
.
The same address or type is entered differently, such as (structsockaddr*)&clnt_add
.
Although type safety is poor, it is a way to overcome the limitations of C language expression.
The type I mentioned means the data type (integer, structure, etc.). Different protocols have different address representations and different structures to use.
If you look at the implementation example of accept()
, you will understand it more easily.
int accept(int sockfd, struct sockaddr* addr, scoklen_t addrlen) {
if (addr->sa_family == AF_INET && addrlen == sizeof(struct sockaddr_in)) {
struct sockaddr_in* address = (struct sockaddr_in*) addr;
address->sin_port;
// ...
} } else if (addr->sa_family == AF_UNIX && addrlen == sizeof(struct sockaddr_un)) {
struct sockaddr_un* address = (struct sockaddr_in*) addr;
address->sun_path;
// ...
}
// ...
}
As shown above, accept() has an implementation that accommodates several types of addr
.
However, addr
is structure sockaddr*
. As a result, compilation errors occur in the following situations:
struct sockaddr_in address;
accept(sock, &address, sizeof(address));
Because &address
is structure sockaddr_in*
rather than structure sockaddr*
.
To avoid this problem, we trick the compiler by force casting as follows:
struct sockaddr_in address;
accept(sock, (struct sockaddr*)&address, sizeof(address));
This is a dangerous enough way. However, the ABI aspect or accept() implementation mentioned above ensures that these codes work properly.
© 2024 OneMinuteCode. All rights reserved.