-
参考:https://stackoverflow.com/questions/12260003/connect-returns-invalid-argument-with-ipv6-address
-
使用ping测试ipv6网络是否连接:
-
ping6 fe80::be30:5bff:fec8:xxxx。报如下错误:connect: Invalid argument。
-
ping6 -I em1 fe80::be30:5bff:fec8:xxxx。使用-I参数指定网络接口名时,ping正常工作。
-
-
ssh连接:
-
ssh root@fe80::be30:5bff:fec8:xxxx。报如下错误:ssh: connect to host fe80::be30:5bff:fec8:xxxx port 22: Invalid argument
-
ssh root@fe80::be30:5bff:fec8:xxxx%em1. ipv6地址后使用%连接网络接口名,连接正常。
-
-
概括如上现象,得出如下结论:fe...开头的ipv6地址,需要指定一个与之相关联的网络接口才能正常工作。
-
tcp客户端demo中,connect函数,需要在参数struct sockaddr_in6结构的sin6_scope_id字段指定网络接口id。可通过命令:ip -d addr。获取网络接口名和网络接口id的对应关系。注意:sin6_scope_id不需要进行字节序转换。
-
ipv6 tcp server示例程序如下:
#include <sys/types.h> // socket
#include <sys/socket.h> // socket
#include <netinet/in.h> // struct sockaddr_incli_client_socket_init(void)
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define IPV6_TCP_SERVER_PORT 4444
int main(int argc, char *argv[])
{
int ret = 0;
int servfd = -1, len = 0;
uint32_t event_flag = 0;
struct sockaddr_in6 servaddr, cliaddr;
servfd = socket(AF_INET6, SOCK_STREAM, 0);
if (-1 == servfd) {
perror("socket");
ret = -1;
goto errexit;
}
int reuse = 1;
ret = setsockopt(servfd,
SOL_SOCKET,
SO_REUSEADDR,
&reuse,
(socklen_t ) sizeof(int));
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin6_family = AF_INET6;
servaddr.sin6_port = htons(IPV6_TCP_SERVER_PORT);
ret = bind(servfd,
(const struct sockaddr *) &servaddr,
(socklen_t ) sizeof(struct sockaddr_in6));
if (-1 == ret) {
perror("bind");
ret = -1;
goto errexit;
}
#define LISTEN_MAX 5
ret = listen(servfd, LISTEN_MAX);
if (-1 == ret) {
perror("listen");
ret = -1;
goto errexit;
}
int epfd = -1;
struct epoll_event event;
epfd = epoll_create(LISTEN_MAX);
if (-1 == ret) {
perror("epoll_create");
ret = -1;
goto errexit;
}
memset(&event, 0, sizeof(struct epoll_event));
event.data.fd = servfd;
event.events = EPOLLIN | event_flag;
epoll_ctl(epfd, EPOLL_CTL_ADD, servfd, &event);
int nfds = 0, connfd = -1;
char read_buf[256];
struct epoll_event events;
socklen_t clilen = sizeof(struct sockaddr_in);
while (1) {
nfds = epoll_wait(epfd, &events, 1, -1);
if (-1 == nfds) {
printf("error occurs\n");
continue;
} else if (0 == nfds) {
printf("timeout\n");
} else {
if (servfd == events.data.fd) {
connfd = accept(servfd, (struct sockaddr *) &cliaddr, &clilen);
if (-1 == connfd) {
perror("accept");
continue;
}
memset(&event, 0, sizeof(struct epoll_event));
event.data.fd = connfd;
event.events = EPOLLIN | event_flag;
epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &event);
printf("new connect\n");
} else {
memset(read_buf, 0, sizeof(read_buf));
len = read(events.data.fd, read_buf, sizeof(read_buf));
if (0 == len) {
printf("peer close\n");
break;
} else {
printf("recv [%s]\n", read_buf);
}
}
}
}
errexit:
return ret;
}
-
ipv6 tcp client示例程序如下:
#include <sys/types.h> // socket
#include <sys/socket.h> // socket
#include <netinet/in.h> // struct sockaddr_incli_client_socket_init(void)
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int ret = 0;
int cli_fd = -1;
char *pc_serv_ip = NULL, *pc_serv_port = NULL;
struct sockaddr_in6 servaddr, cliaddr;
cli_fd = socket(AF_INET6, SOCK_STREAM, 0);
if (-1 == cli_fd) {
perror("socket");
ret = -1;
goto errexit;
}
if (3 != argc) {
printf("\nUsage: ./cli ip port\n");
ret = -1;
goto errexit;
}
pc_serv_ip = argv[1];
pc_serv_port = argv[2];
printf("dest ip=%s, port=%s\r\n", pc_serv_ip, pc_serv_port);
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin6_family = AF_INET6;
servaddr.sin6_port = htons(atoi(pc_serv_port));
ret = inet_pton(AF_INET6, pc_serv_ip, &servaddr.sin6_addr);
if (1 != ret) {
perror("inet_pton");
ret = -1;
goto errexit;
}
//servaddr.sin6_scope_id = htonl(2);
servaddr.sin6_scope_id = 2;
ret = connect(cli_fd, (const struct sockaddr *) &servaddr, (socklen_t) sizeof(servaddr));
if (-1 == ret) {
perror("connect");
goto errexit;
}
printf("Succeed to connect to server\r\n");
char write_buf[256] = {"x"};
while (1) {
memset(write_buf, 0, sizeof(write_buf));
snprintf(write_buf, sizeof(write_buf), "Hello ipv6 server.");
write(cli_fd, write_buf, strlen(write_buf));
break;
}
errexit:
return ret;
}