LINUX 下 ipv6 socket 编程
大家都知道,随着互联网上主机数量的增多,现有的32位IP地址已经不够用了,所以推出了下一代IP地址IPv6,写网络程序的要稍微改变一下现有的网络程序适应IPv6网络是相当容易的事。
对于我们来说就是IP地址变化了,所以程序里在用到IP地址的地方做相应的改变就可以了。
记住:主要是改变程序里设置IP地址和端口等部分的代码。
服务器端源代码如下:
/***********************/
#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
/************关于本文档********************************************
*filename: ipv6-server.c
*purpose: 演示最基本的IPv6网络编程步骤,开启服务接收客户端连接并和客户端通信,互相收发消息
*wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com)
Linux爱好者 Linux知识传播者 SOHO族 开发者 最擅长C语言
*date time:2007-01-29 13:06
*Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途
* 但请遵循GPL
*Thanks to:Google
*Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力
* 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献!
inet_aton() 转换网络主机地址cp为二进制数值,并存储在struct in_addr结构中,即第二个参数*inp,函数返回非0表示cp主机有地有效,返回0表示主机地址无效。
inet_addr
函数转换网络主机地址(如192.168.1.10)为网络字节序二进制值,如果参数char
*cp无效,函数返回-1(INADDR_NONE),这个函数在处理地址为255.255.255.255时也返回
-1,255.255.255.255是一个有效的地址,不过inet_addr无法处理;
inet_ntoa 函数转换网络字节排序的地址为标准的ASCII以点分开的地址,,该函数返回指向点分开的字符串地址的指针,该字符串的空间为静态分配的,这意味着在第二次调用该函数时,上一次调用将会被重写(复盖),所以如果需要保存该串最后复制出来自己管理!
*********************************************************************/
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; //myport:端口号,lisnum最大连接数
char buf[MAXBUF + 1];
if (argv[1])
myport = atoi(argv[1]);//atoi /把字符串转化为整形,
else
myport = 7838;
if (argv[2])
lisnum = atoi(argv[2]);
else
lisnum = 2;
/* if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { */ // IPv4
if ((sockfd = socket(PF_INET6, SOCK_STREAM, 0)) == -1) { // IPv6
perror("socket");
exit(1);
} 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 htons :将主机的无符号短整形数转 换成网络字节顺序。
if (argv[3])
/* my_addr.sin_addr.s_addr = inet_addr(argv[3]); */ // IPv4
inet_pton(AF_INET6, argv[3], &my_addr.sin6_addr); // IPv6
/*#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);
这个函数转换字符串到网络地址,第一个参数af是地址族,转换后存在dst中
inet_pton 是inet_addr的扩展,支持的多地址族有下列:
AF_INET
src为指向字符型的地址,即ASCII的地址的首地址(ddd.ddd.ddd.ddd格式的),函数将该地址
转换为in_addr的结构体,并复制在*dst中
AF_INET6
src为指向IPV6的地址,,函数将该地址
转换为in6_addr的结构体,并复制在*dst中
如果函数出错将返回一个负值,并将errno设置为EAFNOSUPPORT,如果参数af指定的地址族和src格式不对,函数将返回0。
函数inet_ntop进行相反的转换原型如下
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
这个函数转换网络二进制结构到ASCII类型的地址,参数的作用和上面相同,只是多了一个参数socklen_t cnt,他是所指向缓存区dst的大小,避免溢出,如果缓存区太小无法存储地址的值,则返回一个空指针,并将errno置为ENOSPC
*/
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
== -1) {
perror("bind");
exit(1);
} else
printf("binded\n");
if (listen(sockfd, lisnum) == -1) {
perror("listen");
exit(1);
} else
printf("begin listen\n");
while (1) {
len = sizeof(struct sockaddr);
if ((new_fd =
accept(sockfd, (struct sockaddr *) &their_addr,
&len)) == -1) {
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 + 1);
strcpy(buf,
"这是在连接建立成功后向客户端发送的第一个消息\n只能向new_fd这个用accept函数新建立的socket发消息,不能向sockfd这个监听socket发送消息,监听socket不能用来接收或发送消息\n");
/* 发消息给客户端 */
len = send(new_fd, buf, strlen(buf), 0);
if (len < 0) {
printf
("消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n",
buf, errno, strerror(errno));
} else
printf("消息'%s'发送成功,共发送了%d个字节!\n",
buf, len);
bzero(buf, MAXBUF + 1);
/* 接收客户端的消息 */
len = recv(new_fd, buf, MAXBUF, 0);
if (len > 0)
printf("接收消息成功:'%s',共%d个字节的数据\n",
buf, len);
else
printf
("消息接收失败!错误代码是%d,错误信息是'%s'\n",
errno, strerror(errno));
/* 处理每个新连接上的数据收发结束 */
}
close(sockfd);
return 0;
}
每行程序后面的 “//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
/************关于本文档********************************************
*filename: ipv6-client.c
*purpose: 演示最基本的IPv6网络编程步骤,这是个客户端程序,与服务器互相收发消息
*wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com)
Linux爱好者 Linux知识传播者 SOHO族 开发者 最擅长C语言
*date time:2007-01-29 12:56
*Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途
* 但请遵循GPL
*Thanks to:Google
*Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力
* 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献!
*********************************************************************/
int main(int argc, char **argv)
{
int sockfd, len;
/* struct sockaddr_in dest; */ // IPv4
struct sockaddr_in6 dest; // IPv6
char buffer[MAXBUF + 1];
if (argc != 3) {
printf
("参数格式错误!正确用法如下:\n\t\t%s IP地址 端口\n\t比如:\t%s 127.0.0.1 80\n此程序用来从某个 IP 地址的服务器某个端口接收最多 MAXBUF 个字节的消息",
argv[0], argv[0]);
exit(0);
}
/* 创建一个 socket 用于 tcp 通信 */
/* if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { */ // IPv4
if ((sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0) { // 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[2])); // IPv6
/* if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0) { */ // IPv4
if ( inet_pton(AF_INET6, argv[1], &dest.sin6_addr) < 0 ) { // IPv6
perror(argv[1]);
exit(errno);
}
printf("address created\n");
/* 连接服务器 */
if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0) {
perror("Connect ");
exit(errno);
}
printf("server connected\n");
/* 接收对方发过来的消息,最多接收 MAXBUF 个字节 */
bzero(buffer, MAXBUF + 1);
/* 接收服务器来的消息 */
len = recv(sockfd, buffer, MAXBUF, 0);
if (len > 0)
printf("接收消息成功:'%s',共%d个字节的数据\n",
buffer, len);
else
printf
("消息接收失败!错误代码是%d,错误信息是'%s'\n",
errno, strerror(errno));
bzero(buffer, MAXBUF + 1);
strcpy(buffer, "这是客户端发给服务器端的消息\n");
/* 发消息给服务器 */
len = send(sockfd, buffer, strlen(buffer), 0);
if (len < 0)
printf
("消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n",
buffer, errno, strerror(errno));
else
printf("消息'%s'发送成功,共发送了%d个字节!\n",
buffer, len);
/* 关闭连接 */
close(sockfd);
return 0;
}
编译程序用下列命令:
引用:
gcc -Wall ipv6-server.c -o ipv6server
gcc -Wall ipv6-client.c -o ipv6client
LINUX 下 ipv6 socket 编程的更多相关文章
- Linux下网络socket编程——实现服务器(select)与多个客户端通信
一.关于socket通信 服务器端工作流程: 调用 socket() 函数创建套接字 用 bind() 函数将创建的套接字与服务端IP地址绑定 调用listen()函数监听socket() 函数创建的 ...
- Linux下Golang Socket编程原理分析与代码实现
在POSIX标准推出后,socket在各大主流OS平台上都得到了很好的支持.而Golang是自带Runtime的跨平台编程语言,Go中提供给开发者的Socket API是建立在操作系统原生Socket ...
- 网络编程学习笔记:linux下的socket编程
socket是进程通信的一种方式,通过调用一些API可以实现进程间通信,建立连接以及收发信息的过程如下图所示: 这些函数的用法如下: 1.int socket(int protocolFamily, ...
- Linux下TCP/socket编程
写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文! 本博客全网唯一合法URL:ht ...
- Linux下TCP网络编程与基于Windows下C#socket编程间通信
一.linux下TCP网络编程基础,需要了解相关函数 Socket():用于套接字初始化. Bind():将 socket 与本机上的一个端口绑定,就可以在该端口监听服务请求. Listen():使s ...
- ZT Linux系统环境下的Socket编程详细解析
Linux系统环境下的Socket编程详细解析 来自: http://blog.163.com/jiangh_1982/blog/static/121950520082881457775/ 什么是So ...
- Linux下的C编程实战
Linux下的C编程实战(一) ――开发平台搭建 1.引言 Linux操作系统在服务器领域的应用和普及已经有较长的历史,这源于它的开源特点以及其超越Windows的安全性和稳定性.而近年来, Linu ...
- winsock教程- windows下的socket编程(c语言实现)
winsock教程- windows下的socket编程(c语言实现) 使用winsock进行socket 编程 这是一个学习windows下socket编程(c语言)的快速指南.这是因为一下 ...
- Linux下C语言编程实现spwd函数
Linux下C语言编程实现spwd函数 介绍 spwd函数 功能:显示当前目录路径 实现:通过编译执行该代码,可在终端中输出当前路径 代码实现 代码链接 代码托管链接:spwd.c 所需结构体.函数. ...
随机推荐
- Hibernate-04 延迟加载
学习任务 延迟加载 Open Session In View模式 延迟加载 延迟加载(lazy load懒加载)是在真正需要数据时才执行SQL语句进行查询,避免了无谓的性能开销. 延迟加载策略的设置分 ...
- Linux的Network Tunnel技术
Linux的Network Tunnel技术 概要 Linux上可以使用ip tunnel命令创建多种类型的tunnel. 在 man ip-tunnel 中可以得知以下几种类型的tunnel: MO ...
- FastDFS和集中存储方式对比
指标 FastDFS NFS 集中存储设备如NetApp.NAS 线性扩容性 高 差 差 文件高并发访问性能 高 差 一般 文件访问方式 专有API POSIX 支持POSIX 硬件成 ...
- python之操作excel:xlrd、xlwt、xlutiles、枚举函数enumerate()
一.读excel: xlrd-----只能读.不能写 import xlrd book=xlrd.open_workbook(r'E:\BestTest\内容\名单.xlsx') #打开excel s ...
- 最小生成树 Prim算法 Kruskal算法实现
最小生成树定义 最小生成树是一副连通加权无向图中一棵权值最小的生成树. 在一给定的无向图 G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边(即,而 w(u, v) 代表此边的 ...
- <Spring Cloud>入门六 Zuul
1.Zuul 2.操作 2.1 pom <?xml version="1.0" encoding="UTF-8"?> <project xml ...
- Mysql数据库事件使用与示例
1 事件简介 事件(event)是MySQL在相应的时刻调用的过程式数据库对象.一个事件可调用一次,也可周期性的启动,它由一个特定的线程来管理的,也就是所谓的“事件调度器”. 事件和触发器类似,都是在 ...
- Python自动化测试框架——概述
#使用import import unittest #测试用例TestCase ''' 一个测试用例时一个完整的测试流程,包括了环境准备SetUp,测试执行Run,测试环境还原TearDown 一个测 ...
- 交互式数据可视化-D3.js(四)形状生成器
使用JavaScript和D3.js实现数据可视化 形状生成器 线段生成器 var linePath = d3.line() - 使用默认的设置构造一个 line 生成器. linePath.x() ...
- CSS--浮动与定位
*浮动布局能够实现横向多列布局. 1.在网页中,元素有三种布局模型: 1.流动模型(Flow) 2.浮动模型 (Float) 3.层模型(Layer) 流动(Flow)是默认的网页布局模式.流动布局模 ...