一、TCP socket ipv6与ipv4的区别

服务器端源代码如下:

 #include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <arpa/inet.h>
#define MAXBUF 1024
int main(int argc, char **argv)
{
int sockfd, new_fd;
socklen_t len; /* struct sockaddr_in my_addr, their_addr; */ // IPv4
struct sockaddr_in6 my_addr, their_addr; // IPv6 unsigned int myport, lisnum;
char buf[MAXBUF + ]; if (argv[])
myport = atoi(argv[]);
else
myport = ; if (argv[])
lisnum = atoi(argv[]);
else
lisnum = ; /* if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { */ // IPv4
if ((sockfd = socket(PF_INET6, SOCK_STREAM, )) == -) { // IPv6
perror("socket");
exit();
} else
printf("socket created/n"); bzero(&my_addr, sizeof(my_addr));
/* my_addr.sin_family = PF_INET; */ // IPv4
my_addr.sin6_family = PF_INET6; // IPv6
/* my_addr.sin_port = htons(myport); */ // IPv4
my_addr.sin6_port = htons(myport); // IPv6
if (argv[])
/* my_addr.sin_addr.s_addr = inet_addr(argv[3]); */ // IPv4
inet_pton(AF_INET6, argv[], &my_addr.sin6_addr); // IPv6
else
/* my_addr.sin_addr.s_addr = INADDR_ANY; */ // IPv4
my_addr.sin6_addr = in6addr_any; // IPv6 /* if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) */ // IPv4
if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr_in6)) // IPv6
== -) {
perror("bind");
exit();
} else
printf("binded/n"); if (listen(sockfd, lisnum) == -) {
perror("listen");
exit();
} else
printf("begin listen/n"); while () {
len = sizeof(struct sockaddr);
if ((new_fd =
accept(sockfd, (struct sockaddr *) &their_addr,
&len)) == -) {
perror("accept");
exit(errno);
} else
printf("server: got connection from %s, port %d, socket %d/n",
/* inet_ntoa(their_addr.sin_addr), */ // IPv4
inet_ntop(AF_INET6, &their_addr.sin6_addr, buf, sizeof(buf)), // IPv6
/* ntohs(their_addr.sin_port), new_fd); */ // IPv4
their_addr.sin6_port, new_fd); // IPv6 /* 开始处理每个新连接上的数据收发 */
bzero(buf, MAXBUF + );
strcpy(buf,
"这是在连接建立成功后向客户端发送的第一个消息/n只能向new_fd这个用accept函数新建立的socket发消息,不能向sockfd这个监听socket发送消息,监听socket不能用来接收或发送消息/n");
/* 发消息给客户端 */
len = send(new_fd, buf, strlen(buf), );
if (len < ) {
printf
("消息'%s'发送失败!错误代码是%d,错误信息是'%s'/n",
buf, errno, strerror(errno));
} else
printf("消息'%s'发送成功,共发送了%d个字节!/n",
buf, len); bzero(buf, MAXBUF + );
/* 接收客户端的消息 */
len = recv(new_fd, buf, MAXBUF, );
if (len > )
printf("接收消息成功:'%s',共%d个字节的数据/n",
buf, len);
else
printf
("消息接收失败!错误代码是%d,错误信息是'%s'/n",
errno, strerror(errno));
/* 处理每个新连接上的数据收发结束 */
} close(sockfd);
return ;
}

每行程序后面的 “//IPv4” 表示这行代码是在IPv4网络里用的

而“//IPv6” 表示这行代码是在IPv6网络里用的,比较一下,会很容易看到差别的。
客户端源代码如下:

 #include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define MAXBUF 1024
int main(int argc, char **argv)
{
int sockfd, len;
/* struct sockaddr_in dest; */ // IPv4
struct sockaddr_in6 dest; // IPv6
char buffer[MAXBUF + ]; if (argc != ) {
printf
("参数格式错误!正确用法如下:/n/t/t%s IP地址 端口/n/t比如:/t%s 127.0.0.1 80/n此程序用来从某个 IP 地址的服务器某个端口接收最多 MAXBUF 个字节的消息",
argv[], argv[]);
exit();
}
/* 创建一个 socket 用于 tcp 通信 */
/* if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { */ // IPv4
if ((sockfd = socket(AF_INET6, SOCK_STREAM, )) < ) { // IPv6
perror("Socket");
exit(errno);
}
printf("socket created/n"); /* 初始化服务器端(对方)的地址和端口信息 */
bzero(&dest, sizeof(dest));
/* dest.sin_family = AF_INET; */ // IPv4
dest.sin6_family = AF_INET6; // IPv6
/* dest.sin_port = htons(atoi(argv[2])); */ // IPv4
dest.sin6_port = htons(atoi(argv[])); // IPv6
/* if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0) { */ // IPv4
if ( inet_pton(AF_INET6, argv[], &dest.sin6_addr) < ) { // IPv6
perror(argv[]);
exit(errno);
}
printf("address created/n"); /* 连接服务器 */
if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != ) {
perror("Connect ");
exit(errno);
}
printf("server connected/n"); /* 接收对方发过来的消息,最多接收 MAXBUF 个字节 */
bzero(buffer, MAXBUF + );
/* 接收服务器来的消息 */
len = recv(sockfd, buffer, MAXBUF, );
if (len > )
printf("接收消息成功:'%s',共%d个字节的数据/n",
buffer, len);
else
printf
("消息接收失败!错误代码是%d,错误信息是'%s'/n",
errno, strerror(errno)); bzero(buffer, MAXBUF + );
strcpy(buffer, "这是客户端发给服务器端的消息/n");
/* 发消息给服务器 */
len = send(sockfd, buffer, strlen(buffer), );
if (len < )
printf
("消息'%s'发送失败!错误代码是%d,错误信息是'%s'/n",
buffer, errno, strerror(errno));
else
printf("消息'%s'发送成功,共发送了%d个字节!/n",
buffer, len); /* 关闭连接 */
close(sockfd);
return ;
}

编译程序用下列命令:
gcc -Wall ipv6-server.c -o ipv6server
gcc -Wall ipv6-client.c -o ipv6client
你自己的主机有IPv6地址吗?很多人会问,输入ifconfig命令看一下吧:

eth0      链路封装:以太网  硬件地址 00:14:2A:6D:5B:A5  
          inet 地址:192.168.0.167  广播:192.168.0.255  掩码:255.255.255.0
          inet6 地址: fe80::214:2aff:fe6d:5ba5/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  跃点数:1
          接收数据包:30507 错误:0 丢弃:0 过载:0 帧数:0
          发送数据包:26797 错误:0 丢弃:0 过载:0 载波:0
          碰撞:0 发送队列长度:1000 
          接收字节:31461154 (30.0 MiB)  发送字节:4472810 (4.2 MiB)
          中断:185 基本地址:0xe400

lo        链路封装:本地环回  
          inet 地址:127.0.0.1  掩码:255.0.0.0
          inet6 地址: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  跃点数:1
          接收数据包:13 错误:0 丢弃:0 过载:0 帧数:0
          发送数据包:13 错误:0 丢弃:0 过载:0 载波:0
          碰撞:0 发送队列长度:0 
          接收字节:1178 (1.1 KiB)  发送字节:1178 (1.1 KiB)

看到“inet6 地址:”这两行了吗?后面就是你的IPv6地址
启动服务:
./ipv6server 7838 1
或者加上IP地址启动服务:
./ipv6server 7838 1 fe80::214:2aff:fe6d:5ba5
启动客户端测试一下:
./ipv6client ::1/128 7838 

./ipv6client fe80::214:2aff:fe6d:5ba5 7838

二、UDP ipv6例子

UDP服务端:

 #include <unistd.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <string.h>
#define LOCALPORT 8888
int main(int argc,char *argv[])
{
int mysocket,len;
int i=;
struct sockaddr_in6 addr;
int addr_len;
char msg[];
char buf[]; if((mysocket=socket(AF_INET6,SOCK_DGRAM,))<)
{
perror("error:");
return();
}
else
{
printf("socket created ...\n");
printf("socket id :%d \n",mysocket);
} addr_len=sizeof(struct sockaddr_in6);
bzero(&addr,sizeof(addr));
addr.sin6_family=AF_INET6;
addr.sin6_port=htons(LOCALPORT);
addr.sin6_addr=in6addr_any; if(bind(mysocket,(struct sockaddr *)&addr,sizeof(addr))<)
{
perror("connect");
return();
}
else
{
printf("bink ok .\n");
printf("local port : %d\n",LOCALPORT);
}
while()
{
bzero(msg,sizeof(msg));
len = recvfrom(mysocket,msg,sizeof(msg),,(struct sockaddr *)&addr,(socklen_t*)&addr_len);
printf("%d:",i);
i++;
inet_ntop(AF_INET6,&addr.sin6_addr,buf,sizeof(buf));
printf("message from ip %s",buf);
printf("Received message : %s\n",msg);
if(sendto(mysocket,msg,len,,(struct sockaddr *)&addr,addr_len)<)
{
printf("error");
return();
}
}
}

UDP客户端代码:

 #include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/socket.h>
#include <string.h>
#define REMOTEPORT 8888
#define REMOTEIP "::1"
int main(int argc,char *argv[])
{
int mysocket,len;
int i=;
struct sockaddr_in6 addr;
int addr_len;
char msg[];
if((mysocket=socket(AF_INET6,SOCK_DGRAM,))<)
{
perror("error:");
return();
}
else
{
printf("socket created ...\n");
printf("socket id :%d \n",mysocket);
printf("rmote ip : %s\n",REMOTEIP);
printf("remote port :%d \n",REMOTEPORT);
} addr_len=sizeof(struct sockaddr_in6);
bzero(&addr,sizeof(addr));
addr.sin6_family=AF_INET6;
addr.sin6_port=htons(REMOTEPORT);
inet_pton(AF_INET6,REMOTEIP,&addr.sin6_addr); while()
{
bzero(msg,sizeof(msg));
len=read(STDIN_FILENO,msg,sizeof(msg));
if(sendto(mysocket,msg,sizeof(msg),,(struct sockaddr *)&addr,addr_len)<)
{
printf("error");
return();
}
len=recvfrom(mysocket,msg,sizeof(msg),,(struct sockaddr *)&addr,(socklen_t*)&addr_len);
printf("%d:",i);
i++;
printf("Received message : %s\n",msg);
}
}

"::1"相当于ipv4下的lo,即127网段

三、ipv6环境下inet_pton和inet_ntop

附上一段ipv6环境下inet_pton和inet_ntop函数代码

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h> int main(int argc, char **argv)
{
unsigned char buf[sizeof(struct in6_addr)];
int domain, s;
char str[INET6_ADDRSTRLEN]; if(argc != ){
fprintf(stderr, "usage: %s {i4|i6|<num>} string\n", argv[]);
exit(EXIT_FAILURE);
} domain = (strcmp(argv[], "i4") == ) ? AF_INET:(strcmp(argv[], "i6") == ) ? AF_INET6 : atoi(argv[]); //IP字符串 ——》网络字节流
s = inet_pton(domain, argv[], buf);
if(s<=)
{
if( == s)
fprintf(stderr, "Not in presentation format\n");
else
perror("inet_pton");
exit(EXIT_FAILURE);
} //网络字节流 ——》IP字符串
if(inet_ntop(domain, buf, str, INET6_ADDRSTRLEN) == NULL){
perror("inet ntop\n");
exit(EXIT_FAILURE);
}
printf("%s\n", str);
exit(EXIT_SUCCESS);
}

四、兼容IPV4和IPV6地址代码

为了能够兼容ipv4和ipv6,可以组织代码如下:

 #define ADDRESS_BUFFER 50  

 typedef class address
{
private:
short int sin_family; //address family AF_INET or AF_INET6
union
{
char binary_addr4[IPV4_LEN];
char binary_addr6[IPV6_LEN];
}addr;
char readable_addr[ADDRESS_BUFFER]; public:
address();
bool operator == (const address &dst) const;
bool operator != (const address &dst) const { return (*this == dst? false : true );}
bool operator < (const address &dst) const;
const char* get_readable_address() const {return readable_addr;}
int get_family() const {return sin_family;}
bool is_ipv6() const {return sin_family == AF_INET6;}
void set_family(int af) {if(af != AF_INET && af != AF_INET6) return; sin_family = af;}
bool set_from_readable_address(const char* readable_address);
const char* get_binary_data() {return (char*)&addr;}
}address;

这里最重要的函数是set_from_readable_address函数,该函数是整个类的入口,执行该函数需要传入一个可读的IP地址,ipv4应该是"xxx.xxx.xxx.xxx"形式,ipv6应该是如:“ff01::1”或者"ffec:afaf::111"等可读的格式,返回false代表转换格式遇到错误,下面贴上该函数的实现代码,其它函数有兴趣的可以自己实现

 bool address::set_from_readable_address(const char* readable_address)
{
if(readable_address == NULL)
return false;
memset(addr.binary_addr6, , sizeof(addr.binary_addr6));
const char*p = readable_address;
int cnt = ;
for(; *p != '\0';p++)
if(*p == ':')
cnt++;
if(cnt >= )
{
sin_family = AF_INET6;
if( inet_pton(PF_INET6,readable_address,addr.binary_addr6) <= )
return false;
strncpy(readable_addr, readable_address, ADDRESS_BUFFER);
}else
{
sin_family = AF_INET;
if( inet_pton(PF_INET,readable_address,addr.binary_addr4) <= )
return false;
strncpy(readable_addr, readable_address, ADDRESS_BUFFER);
}
return true;
}

IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类的更多相关文章

  1. android 网络编程--socket tcp/ip udp http之间的关系

    网络七层由下往上分别为物理层.数据链路层.网络层.传输层.会话层.表示层和应用层,一般编程人员接触最多的就是应用层和运输层,再往下的就是所谓的媒体层了,不是我们研究的对象. 下面是应用层.运输层,网络 ...

  2. 【网络编程1】网络编程基础-TCP、UDP编程

    网络基础知识 网络模型知识 OSI七层模型:(Open Systems Interconnection Reference Model)开放式通信系统互联参考模型,是国际标准化组织(ISO)提出的一个 ...

  3. 网络编程协议(TCP和UDP协议,黏包问题)以及socketserver模块

    网络编程协议 1.osi七层模型 应用层  表示层  会话层  传输层  网络层  数据链路层  物理层 2.套接字 socket 有两类,一种基于文件类型,一种基于网络类型 3.Tcp和udp协议 ...

  4. 网络编程协议(TCP和UDP协议,粘包问题)以及socketserver模块

    网络编程协议 1.osi七层模型 应用层  表示层  会话层  传输层  网络层  数据链路层  物理层 2.套接字 socket 有两类,一种基于文件类型,一种基于网络类型 3.Tcp和udp协议 ...

  5. 网络编程:tcp、udp、socket、struct、socketserver

    一.TCP.UDP 一.ARP(Address Resolution Protocol)即地址解析协议,用于实现从 IP 地址到 MAC 地址的映射,即询问目标IP对应的MAC地址. 二.在网络通信中 ...

  6. Linux socket网络编程基础 tcp和udp

    Socket TCP网络通信编程 首先,服务器端需要做以下准备工作: (1)调用socket()函数.建立socket对象,指定通信协议. (2)调用bind()函数.将创建的socket对象与当前主 ...

  7. 《UNIX网络编程》TCP客户端服务器例子

    最近在看<UNIX网络编程>(简称unp)和<Linux程序设计>,对于unp中第一个获取服务器时间的例子,实践起来总是有点头痛的,因为作者将声明全部包含在了unp.h里,导致 ...

  8. [javaSE] 网络编程(TCP,UDP,Socket特点)

    UDP特点: 面向无连接,把数据打包发过去,收不收得到我不管 数据大小有限制,一次不能超过64k,可以分成多个包 这是个不可靠的协议 速度很快 视频直播,凌波客户端,feiQ都是UDP协议 TCP特点 ...

  9. UNIX网络编程——Socket/TCP粘包、多包和少包, 断包

    为什么TCP 会粘包 前几天,调试mina的TCP通信, 第一个协议包解析正常,第二个数据包不完整.为什么会这样吗,我们用mina这样通信框架,还会出现这种问题? TCP(transport cont ...

随机推荐

  1. json和数组的区别

    原文地址:https://www.cnblogs.com/zhangjingyun/p/4554054.html 我们都知道,json和数组一样,都可以存数据,但是下面我们来总结一下json和数组的区 ...

  2. PP.io的三个阶段,“强中心”——“弱中心”——“去中心”

    什么是PP.io? PP.io是我和Bill发起的存储项目,目的在于为开发者提供一个去中心化的存储和分发平台,能做到更便宜,更高速,更隐私. 当然做去中心化存储的项目也有好几个,FileCoin,Si ...

  3. NIOS II With uCOSII

    1.如果使用uCOS,那么Qsys中Nios II核就不能使用外部中断控制器(EIC). 2.遇到很迷惑的问题,运行uCOSII的实例代码,总是在第二个OSTimeDlyHMSM(0, 0, 3, 0 ...

  4. PHP中empty、isset和is_null的具体区别?

    1.isset()用来检测一个变量是否已声明; 2.empty()用来检测一个变量是否为空如果有如下情况返回真值: 1)空字符串 2)false 3)空数组 4)NULL 5)0 6)0.0 7)un ...

  5. Redis 存储数组

    我们知道Redis是不可以直接存储数组的. 我们只需在存储数组之前序列化(serialize)一下, 然后获取的时候反序列化(unserialize) 就解决这个问题了!

  6. Mac 日常使用tips

    20180725: windows标准的键盘连接了mac如何映射键盘?最大的好处是可以向后删除,还可以一键PageUP, PageDown ref: https://support.apple.com ...

  7. 获取mysql 配置和目录

    http://bbs.csdn.net/topics/390620630 mysql> show variables like '%dir%';+------------------------ ...

  8. 通过yum安装php7

    Linux下全局安装composer方法: //下载composercurl -sS https://getcomposer.org/installer | php //将composer.phar文 ...

  9. 基于maven构建javaweb项目思路梳理及改进

    需要准备的东西: Jdk. myeclipse. maven包 预装jdk环境 1.maven安装及配置: a)      详见url https://www.cnblogs.com/eagle668 ...

  10. mobilenet之Depthwise +Pointwise

    我们知道,mobilenet是适用于移动端的深度学习网络,主要优点是参数少.模型小.准确率相比一些传统卷积损失少等特点. mobileNet之所以这么ok,是因为引入了Depthwise +Point ...