ipv6: ip地址128位, 格式如: xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
共分8个域, 如有多个域都是0000, 可以省略表示为::
ifconfig里查看网络设备的ipv6 地址:
enp0s25: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.0.250 netmask 255.255.255.0 broadcast 192.168.0.255
inet6 fe80::2ad2:44ff:fe1a:fe6 prefixlen 64 scopeid 0x20
// inet6就是表示ipv6地址
ping ipv6地址: 需要指定使用哪个网络设备发出ping包
ping6 -I enp0s25 fe80::fc80:ecee:20b3:8bc2
ping -6 -I enp0s25 fe80::fc80:ecee:20b3:8bc2 //新版本系统支持
与ipv4的socket通信最大的不同点:
-
创建ipv6的socket时domain指定为AF_INET6:
tcp6_socket = socket(AF_INET6, SOCK_STREAM, 0);
raw6_socket = socket(AF_INET6, SOCK_RAW, protocol);
udp6_socket = socket(AF_INET6, SOCK_DGRAM, protocol);
-
使用新地址结构体来描述:
struct sockaddr_in6 {
sa_family_t sin6_family; /* AF_INET6 */
in_port_t sin6_port; /* port number */
uint32_t sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
uint32_t sin6_scope_id; /* Scope ID (new in 2.4) */
};
struct in6_addr {
unsigned char s6_addr[16]; /* IPv6 address */
};
sin6_family is always set to AF_INET6; sin6_port is the protocol port (see sin_port in ip(7));
sin6_flowinfo is the IPv6 flow identifier; sin6_addr is the 128-bit IPv6 address.
sin6_scope_id is an ID depending on the scope of the address. It is new in Linux 2.4. Linux
supports it only for link-local addresses, in that case sin6_scope_id contains the interface
index (see netdevice(7))
其中sin6_scope_id成员当在与服务器端通信时需要指定使用的网络设备index(可通过ioctl(sd, SIOCGIFINDEX, ...)获取)
- 当使用字符串的ip地址需要与ipv6的128位地址互转时,可用下面两个函数:
#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst); //可把字符串表示的ip地址转换ipv4, ipv6地址
af: AF_INET表示IPV4, AF_INET6表示ipv6
src: 表示字符串的ip地址
dst: 表示存放转换结果的缓冲区地址
返回值为1表示转换成功, 0表示字符串是无效的ip地址, -1表示错误.
const char *inet_ntop(int af, const void *src,
char *dst, socklen_t size); //字ipv4/ipv6地址转换成字符串
tcp测试例子, 服务器端代码:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(void)
{
int sd;
sd = socket(AF_INET6, SOCK_STREAM, 0);
if (sd < 0)
{
perror("socket");
return 1;
}
struct sockaddr_in6 addr = {AF_INET6, htons(10086), 0, IN6ADDR_ANY_INIT};
if (bind(sd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
{
perror("bind");
return 2;
}
listen(sd, 100);
int fd;
char ip[20];
struct sockaddr_in6 peer;
socklen_t len = sizeof(peer);
while (1)
{
fd = accept(sd, (struct sockaddr*)&peer, &len);
if (fd <= 0)
break;
inet_ntop(AF_INET6, &peer.sin6_addr, ip, len);
printf("from %s : fd = %d\n", ip, fd);
}
close(sd);
return 0;
}
客户端代码:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <linux/sockios.h>
#include <net/if.h>
int main(int argc, char *argv[])
{
int sd;
if (argc < 3)
{
printf("usage: %s netdev ipv6_addr \n", argv[0]);
return 1;
}
sd = socket(AF_INET6, SOCK_STREAM, 0);
if (sd < 0)
{
perror("socket");
return 1;
}
struct ifreq req;
strcpy(req.ifr_name, argv[1]);
if (ioctl(sd, SIOCGIFINDEX, &req) < 0)
{
perror("gifindex");
return 2;
}
struct sockaddr_in6 to = {AF_INET6, htons(10086), 0};
inet_pton(AF_INET6, argv[2], &to.sin6_addr);
to.sin6_scope_id = req.ifr_ifindex;
if (connect(sd, (struct sockaddr*)&to, sizeof(to)) < 0)
{
perror("connect");
return 3;
}
close(sd);
return 0;
}
udp测试例子, 接收端:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/sockios.h>
#include <sys/socket.h>
#include <net/if.h>
int main(void)
{
int sd, ret;
sd = socket(AF_INET6, SOCK_DGRAM, 0);
if (sd < 0)
{
perror("socket");
return 1;
}
struct sockaddr_in6 addr = {.sin6_family = AF_INET6,
.sin6_port = htons(10086), .sin6_addr = IN6ADDR_ANY_INIT};
if (bind(sd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
{
perror("bind");
return 1;
}
char data[100], ip[20];
struct sockaddr_in6 peer;
socklen_t len = sizeof(peer);
while (1)
{
ret = recvfrom(sd, data, sizeof(data), 0, (struct sockaddr*)&peer, &len);
if (ret <= 0)
break;
data[ret] = 0;
inet_ntop(AF_INET6, &peer.sin6_addr, ip, len);
printf("rcv from %s : %s\n", ip, data);
}
close(sd);
return 0;
}
发送端代码:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/sockios.h>
#include <sys/ioctl.h>
#include <net/if.h>
int main(void)
{
int sd, i;
sd = socket(AF_INET6, SOCK_DGRAM, 0);
if (sd < 0)
{
perror("socket");
return 1;
}
struct ifreq req;
strcpy(req.ifr_name, "enp0s25");
if (ioctl(sd, SIOCGIFINDEX, &req) < 0)
{
perror("gifindex");
return 2;
}
struct sockaddr_in6 to;
to.sin6_family = AF_INET6;
to.sin6_port = htons(10086);
to.sin6_scope_id = req.ifr_ifindex;
if (inet_pton(AF_INET6, "fe80::20c:29ff:fe34:a9b4", &to.sin6_addr) <= 0)
{
perror("pton");
return 2;
}
char data[100];
for (i = 0; i < 10; i++)
{
sprintf(data, "ipv6 udp test %d\n", i);
if (sendto(sd, data, strlen(data), 0, (struct sockaddr*)&to, sizeof(to)) < 0)
{
perror("sendto");
}
}
close(sd);
return 0;
}