一、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. Python的socket

    第一部分socket的简单示例 服务器部分: """ Description: Author:Nod Date: Record: #------------------- ...

  2. Scrapy实战篇(三)之爬取豆瓣电影短评

    今天的主要内容是爬取豆瓣电影短评,看一下网友是怎么评价最近的电影的,方便我们以后的分析,以以下三部电影:二十二,战狼,三生三世十里桃花为例. 由于豆瓣短评网页比较简单,且不存在动态加载的内容,我们下面 ...

  3. [UE4]Throbber,横向动态图标

    一.Throbber跟Circular Throbber一样,都是用来提示玩家后台有数据正在加载中. 二.Throbber是横向显示动态图标.其他方面跟Circular Throbber一样.Circ ...

  4. laydate.js在火狐下的定位问题

    这个情况不知道在火狐的什么情况下会出现这个问题,但是他的demo定位在火狐下是没有问题的. 正常情况下展示位置是这样的 但是呢,在我的火狐下展示的位置是这样的. 哎,默默的读源码吧: 源码: 修改后的 ...

  5. 自己动手实现JDK动态代理

    出自:作者:孤独烟  http://rjzheng.cnblogs.com/ ------------------------------------------------------------- ...

  6. 如何正确实现 Java 中的 HashCode

    相等 和 Hash Code 从一般角度来看,Equality 是不错的,但是 hash code 更则具技巧性.如果我们在 hash code上多下点功夫,我们就能了解到 hash code 就是用 ...

  7. 定位JVM内存溢出问题思路总结

    JVM的内存溢出问题,是个常见而有时候有非常难以定位的问题.定位内存溢出问题常见方法有很多,但是其实很多情况下可供你选择的有效手段非常有限.很多方法在一些实际场景下没有实用价值.这里总结下我的一些定位 ...

  8. IDEA VM设置

    1.IDEA vm options -server -Xms800m -Xmx800m -XX:PermSize=64M -XX:MaxNewSize=256m -XX:MaxPermSize=128 ...

  9. windows共享文件夹权限设置

    权限设置及更改,最好在右键属性里面, 在计算机管理,共享文件夹->共享里面修改,有时候会不生效. windows的凭据修改,在用户注销后才会生效.

  10. Spring中Bean及@Bean的理解

    Spring中Bean及@Bean的理解 Bean在Spring和SpringMVC中无所不在,将这个概念内化很重要,下面分享一下我的想法: 一.Bean是啥 1.Java面向对象,对象有方法和属性, ...