Linux网络编程实例解析
***************************************************************************************************************************
作者:EasyWave 时间:2013.01.19
类别:Linux 应用实例源码 声明:转载,请保留链接
注意:如有错误,欢迎指正。这些是我学习的日志文章......
***************************************************************************************************************************
这段时间,因为项目的需要,了解了一下USBtoNet的驱动,同时采用IOCTL来设置MAC的地址,检测网卡的连接状态等等,因此,就从网络上了解了一下关于网络编程方面的知识.一般来说:Linux网络程序与内核交互的方法是通过ioctl来实现的,ioctl与网络协议栈进行交互,可得到网络接口的信息,网卡设备的映射属性和配置网络接口.并且还能够查看,修改,删除ARP高速缓存的信息,所以,我们先来了解一下ioctl函数的具体实现.
函数形式:
#include <sys/ioctl.h>
int ioctl(int d, int request, ...);
类别 |
Request |
说明 |
数据类型 |
套 接 口 |
SIOCATMARK SIOCSPGRP SIOCGPGRP |
是否位于带外标记 设置套接口的进程ID或进程组ID 获取套接口的进程ID或进程组ID |
int int int |
文 件 |
FIONBIN FIOASYNC FIONREAD FIOSETOWN FIOGETOWN |
设置/清除非阻塞I/O标志 设置/清除信号驱动异步I/O标志 获取接收缓存区中的字节数 设置文件的进程ID或进程组ID 获取文件的进程ID或进程组ID |
int int int int int |
接 口 |
SIOCGIFCONF SIOCSIFADDR SIOCGIFADDR SIOCSIFFLAGS SIOCGIFFLAGS SIOCSIFDSTADDR SIOCGIFDSTADDR SIOCGIFBRDADDR SIOCSIFBRDADDR SIOCGIFNETMASK SIOCSIFNETMASK SIOCGIFMETRIC SIOCSIFMETRIC SIOCGIFMTU SIOCxxx |
获取所有接口的清单 设置接口地址 获取接口地址 设置接口标志 获取接口标志 设置点到点地址 获取点到点地址 获取广播地址 设置广播地址 获取子网掩码 设置子网掩码 获取接口的测度 设置接口的测度 获取接口MTU (还有很多取决于系统的实现) |
struct ifconf struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq |
ARP |
SIOCSARP SIOCGARP SIOCDARP |
创建/修改ARP表项 获取ARP表项 删除ARP表项 |
struct arpreq struct arpreq struct arpreq |
路 由 |
SIOCADDRT SIOCDELRT |
增加路径 删除路径 |
struct rtentry struct rtentry |
流 |
I_xxx |
相关数据结构:
1):网络接口请求结构ifreq
struct ifreq {
#define IFHWADDRLEN 6 //6个字节的硬件地址,即MAC
union { char ifrn_name[IFNAMESIZ]; //网络接口名称
}ifr_ifrn;
union { struct sockaddr ifru_addr; //本地IP地址
struct sockaddr ifru_dstaddr;//目标IP地址
struct sockaddr ifru_broadaddr;//广播IP地址
struct sockaddr ifru_netmask;//本地子网掩码地址
struct sockaddr ifru_hwaddr;//本地MAC地址
short ifru_flags;//网络接口标记
int ifru_ivalue;//不同的请求含义不同
struct ifmap ifru_map;//网卡地址映射
int ifru_mtu;//最大传输单元
char ifru_slave[IFNAMSIZ];//占位符
char ifru_newname[IFNAMSIZE];//新名称
void __user* ifru_data;//用户数据
struct if_settings ifru_settings;//设备协议设置
}ifr_ifru; }
#define ifr_name ifr_ifrn.ifrn_name;//接口名称
#define ifr_hwaddr ifr_ifru.ifru_hwaddr;//MAC
#define ifr_addr ifr_ifru.ifru_addr;//本地IP
#define ifr_dstaddr ifr_ifru.dstaddr;//目标IP
#define ifr_broadaddr ifr_ifru.broadaddr;//广播IP
#define ifr_netmask ifr_ifru.ifru_netmask;//子网掩码
#define ifr_flags ifr_ifru.ifru_flags;//标志
#define ifr_metric ifr_ifru.ifru_ivalue;//接口侧度
#define ifr_mtu ifr_ifru.ifru_mtu;//最大传输单元
#define ifr_map ifr_ifru.ifru_map;//设备地址映射
#define ifr_slave ifr_ifru.ifru_slave;//副设备
#define ifr_data ifr_ifru.ifru_data;//接口使用 #define ifr_ifrindex ifr_ifru.ifru_ivalue;//网络接口序号 #define ifr_qlen ifr_ifru.ifru_ivalue;//传输单元长度 #define ifr_newname ifr_ifru.ifru_newname;//新名称 #define ifr_seeting ifr_ifru.ifru_settings;//设备协议设置
2):网卡设备属性ifmap
struct ifmap { //网卡设备的映射属性
unsigned long mem_start;//开始地址
unsigned long mem_end;//结束地址
unsigned short base_addr;//基地址
unsigned char irq;//中断号
unsigned char dma;//DMA
unsigned char port;//端口
}
3):网络配置接口ifconf
struct ifconf { //网络配置结构体是一种缓冲区
int ifc_len;//缓冲区ifr_buf的大小
union {
char__user *ifcu_buf; //绘冲区指针
struct ifreq__user* ifcu_req;//指向ifreq指针
}ifc_ifcu;
};
#define ifc_buf ifc_ifcu.ifcu_buf;//缓冲区地址
#define ifc_req ifc_ifcu.ifcu_req;//ifc_req地址
4):ARP高速缓存操作arpreq
struct arpreq{
struct sockaddr arp_pa;//协议地址
struct sockaddr arp_ha;//硬件地址
int arp_flags;//标记
struct sockaddr arp_netmask;//协议地址的子网掩码
char arp_dev[];//查询网络接口的名称
}
ARP高速缓存操作,包含IP地址和硬件地址的映射表, 操作ARP高速缓存的命令字 SIOCDARP,SIOCGARP,SIOCSARP分别是删除ARP高速缓存的一条记录,获得ARP高速缓存的一条记录和修改ARP高速缓存的一条记录
相关例子[以下为网络摘录:已经上机验证过]:
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <fcntl.h>
#include <net/if.h> int main(int argc, char*argv[]) {
int s,sv6;
int err;
s = socket(AF_INET, SOCK_DGRAM, );
if (s < ) {
perror("socket error");
return -;
} struct ifreq ifr;
ifr.ifr_ifindex = ; //获得第2个网络接口的名称
err = ioctl(s, SIOCGIFNAME, &ifr);
if (err) {
perror("index error");
} else {
printf("the %dst interface is:%s\n", ifr.ifr_ifindex, ifr.ifr_name);
} memcpy(ifr.ifr_name, "eth0", );
err = ioctl(s, SIOCGIFFLAGS, &ifr);
if (!err) {
printf("SIOCGIFFLAGS:%d\n", ifr.ifr_flags);
}
err = ioctl(s, SIOCGIFMTU, &ifr);
if (!err) {
printf("SIOCGIFMTU:%d\n", ifr.ifr_mtu);
} err = ioctl(s, SIOCGIFHWADDR, &ifr);
if (!err) {
unsigned char* hw = ifr.ifr_hwaddr.sa_data;
printf("SIOCGIFHWADDR:%02x:%02x:%02x:%02x:%02x:%02x\n", hw[], hw[],
hw[], hw[], hw[], hw[]);
} err = ioctl(s, SIOCGIFMAP, &ifr);
if (!err) {
printf(
"SIOCGIFMAP,mem_start:%d,mem_end:%d,base_addr:%d,ifr_map:%d,dma:%d,port:%d\n",
ifr.ifr_map.mem_start, ifr.ifr_map.mem_end,
ifr.ifr_map.base_addr, ifr.ifr_map.irq, ifr.ifr_map.dma,
ifr.ifr_map.port);
} err = ioctl(s, SIOCGIFINDEX, &ifr);
if (!err) {
printf("SIOCGIFINDEX:%d\n", ifr.ifr_ifindex);
} err = ioctl(s, SIOCGIFTXQLEN, &ifr);
if (!err) {
printf("SIOCGIFTXQLEN:%d\n", ifr.ifr_qlen);
} struct sockaddr_in *sin = (struct sockaddr_in*) &ifr.ifr_addr; //保存的是二进制IP
char ip[]; //字符数组,存放字符串
memset(ip, , );
err = ioctl(s, SIOCGIFADDR, &ifr);
if (!err) {
inet_ntop(AF_INET, &sin->sin_addr.s_addr, ip, ); //转换的字符串保存到ip数组中,第二个参数是要转换的二进制IP指针,第三个参数是转换完成存放IP的缓冲区,最后一个参数是缓冲区的长度
printf("SIOCGIFADDR:%s\n", ip);
} err = ioctl(s, SIOCGIFDSTADDR, &ifr);
if (!err) {
inet_ntop(AF_INET, &sin->sin_addr.s_addr, ip, );
printf("SIOCGIFDSTADDR:%s\n", ip);
} err = ioctl(s, SIOCGIFNETMASK, &ifr);
if (!err) {
inet_ntop(AF_INET, &sin->sin_addr.s_addr, ip, );
printf("SIOCGIFNETMASK:%s\n", ip);
} memset(&ifr, , sizeof(ifr));
memcpy(ifr.ifr_name, "eth0", );
ioctl(s, SIOCGIFBRDADDR, &ifr);
struct sockaddr_in *broadcast = (struct sockaddr_in*) &ifr.ifr_broadaddr; inet_ntop(AF_INET, &broadcast->sin_addr.s_addr, ip, ); //inet_ntop将二进制IP转换成点分十进制的字符串
printf("BROADCAST IP:%s\n", ip);
close(s);
}
实例二:[修改代码后,已经上机验证过] MAC地址的设置和获取
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
typedef unsigned char u8 #define LOGD(...) do {printf(__VA_ARGS__); printf("\n");} while(0) int set_mac(u8* addr, int len);
int get_mac(u8* addr, int len); int main(int argc, char*argv[])
{
int ret = ;
u8 addr[] = {0x00, 0x00, 0x00, 0x61, 0x20, 0x58}; ret = set_mac(addr, );
if (ret < )
{
LOGD("set_mac() error");
return ;
}
LOGD("set_mac() done");
ret = get_mac(addr, );
if (ret < )
{
LOGD("get_mac() error");
return ;
}
LOGD("get_mac() done");
char buf[] = {};
snprintf(buf, , "%02x:%02x:%02x:%02x:%02x:%02x",
addr[], addr[], addr[], addr[], addr[], addr[]);
LOGD("%s", buf);
return ;
} int set_mac(u8* addr, int len)
{
int s;
int ret;
struct ifreq ifr;
if (len < )
{
LOGD("set_mac(), invalid length");
return -;
}
s = socket(PF_INET, SOCK_DGRAM, );
if (s < )
{
LOGD("socket() error: %s", strerror(errno));
return -;
}
strcpy(ifr.ifr_ifrn.ifrn_name, "usb0");
ifr.ifr_ifru.ifru_hwaddr.sa_family = ;
memcpy(ifr.ifr_ifru.ifru_hwaddr.sa_data, addr, );
ret = ioctl(s, SIOCSIFHWADDR, &ifr);
if (ret != )
{
LOGD("ioctl(SIOCSIFHWADDR) error: %d(%s)", errno, strerror(errno));
return -;
}
return ;
} int get_mac(u8* addr, int len)
{
int s;
int ret;
struct ifreq ifr; if (len < )
{
LOGD("get_mac(), invalid length");
return -;
}
s = socket(PF_INET, SOCK_DGRAM, );
if (s < )
{
LOGD("socket() error: %s", strerror(errno));
return -;
}
strcpy(ifr.ifr_ifrn.ifrn_name, "usb0");
ret = ioctl(s, SIOCGIFHWADDR, &ifr);
if (ret != )
{
LOGD("ioctl(SIOCSIFHWADDR) error: %s", strerror(errno));
return -;
}
memcpy(addr, ifr.ifr_ifru.ifru_hwaddr.sa_data, );
return ;
}
实例三:网卡连接状态[修改后,已经上机验证]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/if.h> typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned char u8;
typedef unsigned long long u64 #include <linux/sockios.h>
#include <linux/ethtool.h> int get_netlink_status(const char *if_name); int main(int argc, char* argv[])
{
if(argc != )
{
fprintf(stderr, "usage: %s <ethname>.\n", argv[]);
return -;
}
if(getuid() != )
{
fprintf(stderr, "Netlink Status Check Need Root Power.\n");
return ;
} printf("Net link status: %s.\n", get_netlink_status(argv[])==?"up":"down");
return ;
}
// if_name like "ath0", "eth0". Notice: call this function
// return value:
// -1 -- error , details can check errno
// 1 -- interface link up
// 0 -- interface link down.
int get_netlink_status(const char *if_name)
{
int skfd;
struct ifreq ifr;
struct ethtool_value edata;
edata.cmd = ETHTOOL_GLINK;
edata.data = ;
memset(&ifr, , sizeof(ifr));
strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name) - );
ifr.ifr_data = (char *) &edata;
if (( skfd = socket( AF_INET, SOCK_DGRAM, )) == )
return -;
if(ioctl( skfd, SIOCETHTOOL, &ifr ) == -)
{
close(skfd);
return -;
}
close(skfd);
return edata.data;
}
Linux网络编程实例解析的更多相关文章
- Linux多线程编程实例解析
Linux系统下的多线程遵循POSIX线程接口,称为 pthread.编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a.顺便说一下,Linux ...
- Linux 网络编程实例
/*socket->bind->listen->accept->recv/recvfrom->send/sendto->close 客户端:socket->c ...
- Linux网络编程——原始套接字实例:MAC 头部报文分析
通过<Linux网络编程——原始套接字编程>得知,我们可以通过原始套接字以及 recvfrom( ) 可以获取链路层的数据包,那我们接收的链路层数据包到底长什么样的呢? 链路层封包格式 M ...
- 很全的linux网络编程技巧
本文转载自:http://www.cnblogs.com/jfyl1573/p/6476607.html 1. LINUX网络编程基础知识 1 1.1. TCP/IP协议概述 1 1.2. OSI参考 ...
- Linux网络编程&内核学习
c语言: 基础篇 1.<写给大家看的C语言书(第2版)> 原书名: Absolute Beginner's Guide to C (2nd Edition) 原出版社: Sams 作者: ...
- linux网络编程_1
本文属于转载,稍有改动,以利于学习. (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个 ...
- Linux网络编程入门 (转载)
(一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...
- [转] - Linux网络编程 -- 网络知识介绍
(一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...
- 【转】Linux网络编程入门
(一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...
随机推荐
- c#音乐播放器(欣赏)
设置界面 Mini模式 播放器使用C#编写,用到了大量的自定义控件,播放是调用windows API. 现在只是完成了本地音乐功能,下一步我将要做歌词同步及网络音乐 当然,完成以后我将一步一步教大家做 ...
- 最简洁粗暴版的虚拟用户配置FTP
最简洁粗暴版的虚拟用户配置FTP yum安装FTP: yum install vsftpd pam* db4* -y 设置为系统服务:chkconfig –level 35 vsftpd on 2.v ...
- ASP.NET状态保持:ViewState
ViewState是ASP.NET的.aspx页面特有的,是页面级的状态保持.一般用在内网系统和网站后台. namespace WebFormTest.TestCollect { public par ...
- http://www.shanghaihaocong.com-WORDPRESS开发的企业主题站
wordpress是世界上使用最多的php开源博客系统,功能强大,而且拥有众多的插件,可扩展性强. 最近,我也用它做了一个企业网站,欢迎浏览:http://www.shanghaihaocong.co ...
- js 实现栈
function Stack() { this.dataStore = []; this.top = 0; this.push=push; this.pop=pop; this.peek=peek; ...
- XP极限编程
13个核心实战 团队协作(Whole Team) 规划策略(The Planning Game) 软件发布计划(ReleasePlanning) 周期开发计划(IterationPlanning) ...
- nginx+php与apache+php性能对比
测试工具http_load相同的动态页面测试,相同的硬件资源,相同并发,相同请求数量的前提下,nginx+php比apache+php的性能要 差,而且如果请求的压力大于硬件资源的承受能力,nginx ...
- php 实现多线程
通过php的Socket方式实现php程序的多线程.php本身是不支持多线程的,那么如何在php中实现多线程呢?可以想一下,WEB服务器本身都是支持多线程的.每一个访问者,当访问WEB页面的时候,都将 ...
- Nginx配置:http重定向,URLRewrite,一个简单框架的配置思路
一个重定向的应用配置: server { listen 8000; server_name localhost; root F:/home/projects/test; index ...
- 添加TextView隐藏进度条的方法
在TextView中添加 android:scrollbars="vertical" android:singleLine="false" 在Activity代 ...