使用sockaddr_storage的API

Nan*_*nda 20 sockets winsock2

我正在尝试做一些与IP无关的编码,并且根据各种来源的建议,我尝试使用sockaddr_storage.但是,所有API调用(getaddrinfo,getnameinfo)仍然依赖于struct sockaddr.他们之间的铸造并不是一个很好的选择,gves会遇到很多其他问题.

并且单独转换为sockaddr_in和sockaddr_in6会破坏我尝试使用sockaddr_storage的目的.

任何在开发简单的客户端服务器套接字应用程序时有效使用sockaddr_storage的人.

sel*_*bie 25

联合进行IPV6和IPV4编程的问题在于纯sockaddr结构本身不足以容纳sockaddr_in6.因此,如果你需要盲目地传递一个可能是sockaddr_in或sockaddr_in6的地址,那么sockaddr_storage更容易使用.

在一天结束时,无论您使用的是sockaddr_in,sockaddr_in6还是sockaddr_storage,您都必须转发这些指针以调用sendto,recvfrom,connect,accept和许多其他套接字函数.它只是套接字编程的一个细微差别.放开做不安全事情的感觉.你的代码没问题.

现在,当编写适用于IPV4和IPV6的网络代码时,您可以轻松陷入拥有大量switch语句来处理不同网络类型的陷阱.然后代码变得如下:

if (addr.ss_family == AF_INET)
    sendto(sock, buffer, len, 0, (sockaddr*)&addr, sizeof(sockaddr_in))
else (addr.ss_family == AF_INET6)
    sendto(sock, buffer, len, 0, (sockaddr*)&addr, sizeof(sockaddr_in6));
Run Code Online (Sandbox Code Playgroud)

然后那种类型的"if family == AF_INET"表达式可以很容易地反复重复.这就是你想要避免的.

假设您使用的是C++,您会发现套接字地址对象的抽象类非常有用.我在这里这里有一个关于github的例子.CSocketAddress类由{sockaddr,sockaddr_in,sockaddr_in6}的联合支持,并且可以使用sockaddr_storage构造.如果我在开始这个课之前就已经知道了sockaddr_storage,我会用它而不是联合的东西.无论如何,它允许我编写如下代码:

CSocketAddress addr;
...
sendto(sock, buffer, len, 0, addr.GetSockAddr(), addr.GetSockAddrLength());
Run Code Online (Sandbox Code Playgroud)

同样,"accept"语句如下所示:

sockaddr_storage addrstorage = {};
int len = sizeof(sockaddr_storage);
accept(sock, (sockaddr*)&addrstorage, &len);

CSocketAdddress addr(addrstorage); // construct an address object to pass around everywhere else
Run Code Online (Sandbox Code Playgroud)

这对于调用bind,send和recv的代码路径非常有用.现在,我的STUN服务器和客户端代码路径不再需要知道有关套接字地址的族类型的任何信息.他们只使用"CSocketAddress"对象.唯一的IPV4和IPV6特定代码是在客户端和服务器初始化期间 - 实际构造地址对象时.幸运的是,这也被部分抽象出来了.

您可能还想在此处仔细阅读辅助函数.还有一些更有用的东西,用于以IP无关的方式解析主机名,枚举适配器等.这是Linux代码,但其中一些应该映射到Windows和winsock.

我几乎完成了对此代码库的TCP支持.在添加对SOCK_STREAM的支持的过程中,我不必进行单个更改,也不必添加任何新代码来处理IPV4和IPV6地址结构的差异.