linux ipv6 tcp和udp网络编程

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通信最大的不同点:

  1. 创建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);
  1. 使用新地址结构体来描述:
    
           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, ...)获取)
  1. 当使用字符串的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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值