一对简单的IPV6 SOCKET代码
一对简单的IPV6 SOCKET代码,包括服务端ipv6_server.c及客户端ipv6_client.c
服务端ipv6_server.c
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#define MAXLINE 1024
int main(int argc, char **argv)
{
int listenfd, connfd;
socklen_t len;
char buff[MAXLINE];
struct sockaddr_in6 servaddr, cliaddr;
//第一个参数指定AF_INET6来创建一个ipv6监听套接字
listenfd = socket(AF_INET6, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
//servaddr的地址族指定AF_INET6
servaddr.sin6_family = AF_INET6;
//地址使用通配符
servaddr.sin6_addr = in6addr_any;
//端口使用9999
servaddr.sin6_port = htons(9999);
bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
listen(listenfd, 1);
for ( ; ; )
{
len = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &len);
sprintf(buff, "hello");
write(connfd, buff, strlen(buff));
close(connfd);
}
}
需要注意的是,在ipv4中,地址通配符可以直接使用0来赋值,即
servaddr.sin_addr.s_addr = 0
而在ipv6的编程中不能用0直接赋值,原因是ipv6的地址是存放在一个长度为16的unit8_t数组中的。
客户端ipv6_client.c
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <netdb.h>
#define MAXLINE 1024
void mygetaddinfo(struct sockaddr_in6 *servaddr, char *addr)
{
struct addrinfo *ai, *hints;
memset(hints, 0, sizeof(struct addrinfo));
//只要ipv6地址族的结果
hints->ai_family = AF_INET6;
if((getaddrinfo(addr, "9999", hints, &ai)) != 0)
{
perror("IN GETADDRINFO()");
exit(1);
}
*servaddr = *(struct sockaddr_in6 *)ai->ai_addr;
//指定使用的接口
servaddr->sin6_scope_id = 2;
}
int main(int argc, char **argv)
{
int sockfd, n;
struct sockaddr_in6 servaddr;
char recvline[MAXLINE];
socklen_t len;
if (argc != 2)
{
printf("INPUT ADDRESS!");
exit(1);
}
if ( (sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0)
{
perror("SOCKET");
exit(1);
}
bzero(&servaddr, sizeof(servaddr));
mygetaddinfo(&servaddr, argv[1]);
len = sizeof(servaddr);
if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
{
perror("CONNEXT");
exit(1);
}
n = read(sockfd, recvline, MAXLINE);
recvline[n] = 0;
printf("%s\n", recvline);
exit(0);
}
在客户端的代码中,使用了getaddrinfo(char *, char *, struct addrinfo *, struct addrinfo **)
来获取服务端的sockaddr_in6结构体(如果已有地址串及已确定的端口,这调用并没有必要)。值得注意的是,如果使用的链路本地地址(Link-Local Address,以fe80:打头),则必须指定sockaddr_in6中的sin6_scope_id成员,其成员的值可以通过ip link
命令获得,为对应接口前的数字:
sunminming@sunminming:~$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:47:bc:c8 brd ff:ff:ff:ff:ff:ff
如果使用的ipv6的环回地址::1
也可以不用指定sin6_scope_id成员。