关于ipv6网络编程方式
1. 通常我们使用的都是ipv4的方式来进行网路编程通信,本次介绍的是ipv6方式通信方式。
直接根据代码实例来说明,以及使用中需要注意事项。
2在linux环境下,我们使用ifconfig命令查询网卡信息如下:
如上图所示,inet6中两个ipv6地址,这连个地址是有区别的,就是尾部的Global和Link两个关键字。要想使用ipv6进行网路通信,不能使用Link标识的inet6字段,因为该地址私有地址,供给内核使用。所以需要我们使用手动添加相应的ipv6地址且标识为Globalinet6地址来进行通信。如果网卡没有该标识的inet6地址,可手动添加。命令如下:
顺带介绍下ifconfig命令的参数含义,如下图所示:
例如:
ifconfig eth0 add 2001:da8:e000::1:1:1,
之后在使用ifconfig命令即可查看上图所示带有Global标识的inet6地址。好了,不多说,直接来看在tcp下使用inet6地址通信的代码实现方式。
3.Tcp通信代码使用举例
Tcp方式:
Server.cpp:
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
using namespace std;
void* echo(void* argc){
while(1){
int confd = *(int*)argc;
char buff[1024] = {0};
int rec_len = recv(confd,buff,1024,0);
cout<<"recv info is "<<buff<<endl;
sleep(1);
}
}
int main(int argc,char** argv){
int sockfd,acpfd;
string ipv6 = "";
if(argc == 2){
ipv6.assign(argv[1]);
}else{
return -1;
}
int ipv6_port = 9000;
struct sockaddr_in6 sockaddr_ipv6,cli_ipv6;
sockfd = socket(AF_INET6,SOCK_STREAM,0);
if(sockfd == -1){
return -1;
}
sockaddr_ipv6.sin6_family = AF_INET6;
sockaddr_ipv6.sin6_port = htons(ipv6_port);
if(argc == 2){
inet_pton(AF_INET6,ipv6.c_str(),&sockaddr_ipv6.sin6_addr);
}else{
sockaddr_ipv6.sin6_addr = in6addr_any;
}
//ipv6结构体
// struct sockaddr_in6 {
// __uint8_t sin6_len; /* length of this struct(sa_family_t) */
// sa_family_t sin6_family;/* AF_INET6 (sa_family_t) */
// in_port_t sin6_port; /* Transport layer port # (in_port_t) */
// __uint32_t sin6_flowinfo;/* IP6 flow information */
// struct in6_addr sin6_addr;/* IP6 address */
// __uint32_t sin6_scope_id;/* scope zone index */
// };
if(bind(sockfd,(struct sockaddr*)&sockaddr_ipv6,sizeof(sockaddr_ipv6)) == -1){
return -1;
}
if(listen(sockfd,1024) == -1){
return -1;
}
while(1){
socklen_t len = sizeof(cli_ipv6);
acpfd = accept(sockfd,(struct sockaddr*)&cli_ipv6,&len);
cout<<"accept a connect"<<acpfd<<endl;
if(acpfd == -1){
continue;
}
pthread_t id;
if(0 != pthread_create(&id,NULL,echo,(void*)&acpfd)){
continue;
}
sleep(1);
}
close(acpfd);
close(sockfd);
return 0;
}
Client.cpp
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
using namespace std;
int main(int argc,char** argv){
int sockfd,acpfd;
string ipv6 = "";
ipv6.assign(argv[1]);
int ipv6_port = 9000;
struct sockaddr_in6 sockaddr_ipv6;
sockfd = socket(AF_INET6,SOCK_STREAM,0);
if(sockfd == -1){
cout<<"socker is failed"<<endl;
return -1;
}
sockaddr_ipv6.sin6_family = AF_INET6;
sockaddr_ipv6.sin6_port = htons(ipv6_port);
inet_pton(AF_INET6,ipv6.c_str(), &sockaddr_ipv6.sin6_addr);
// struct sockaddr_in6 {
// __uint8_t sin6_len; /* length of this struct(sa_family_t) */
// sa_family_t sin6_family;/* AF_INET6 (sa_family_t) */
// in_port_t sin6_port; /* Transport layer port # (in_port_t) */
// __uint32_t sin6_flowinfo;/* IP6 flow information */
// struct in6_addr sin6_addr;/* IP6 address */
// __uint32_t sin6_scope_id;/* scope zone index */
// };
if(connect(sockfd,(struct sockaddr*)&sockaddr_ipv6,sizeof(sockaddr_ipv6)) == -1){
perror("connect:");
return -1;
}
char buff[]={"Welcome to python world !"};
while(1){
cout<<"will send data is "<<buff<<endl;
int snd_len = send(sockfd,buff,sizeof(buff),0);
if(snd_len <= 0){
continue;
}
sleep(1);
}
close(sockfd);
return 0;
}
编译代码:
g++ -g tcp_ser_ipv6.cpp -o tcp_ser_ipv6 -lpthread
g++ -g tcp_cli_ipv6.cpp -o tcp_cli_ipv6 -lpthread
结果如下:
注:(如果在同一网段中的不同机器上进行通信连接,需注意防火墙是否关闭,针对inet6地址的防火墙它有自己的防火墙名为ip6tables,关闭即可,负责客户端进行连接是会出现connect:: Permission denied错误,或者在ip6tables防火墙配置中配置对应的端口放行即可,在udt封装的协议中,如果防火墙未关闭,会出现Connection setup failure: connection time out.将在后面介绍udt的使用方式,具体配置可参考博主中的socket连接标题的短文介绍过程)。
查看防火墙状态:service ip6tables status
关闭防火墙:service ip6tables stop