Accept() function question

Asked 2 years ago, Updated 2 years ago, 65 views

serv_sock=socket(PF_INET, SOCK_STREAM, 0);

//...

clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_addr,&clnt_addr_size); 

acceptI understand what the argument roles of the function mean. However,

I don't know what it means to have *& in (structsockaddr*)&clnt_add.

pointer socket c network

2022-09-20 11:35

1 Answers

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.


2022-09-20 11:35

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.