***************************************************************************************************************************
作者: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网络编程实例解析的更多相关文章

  1. Linux多线程编程实例解析

    Linux系统下的多线程遵循POSIX线程接口,称为 pthread.编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a.顺便说一下,Linux ...

  2. Linux 网络编程实例

    /*socket->bind->listen->accept->recv/recvfrom->send/sendto->close 客户端:socket->c ...

  3. Linux网络编程——原始套接字实例:MAC 头部报文分析

    通过<Linux网络编程——原始套接字编程>得知,我们可以通过原始套接字以及 recvfrom( ) 可以获取链路层的数据包,那我们接收的链路层数据包到底长什么样的呢? 链路层封包格式 M ...

  4. 很全的linux网络编程技巧

    本文转载自:http://www.cnblogs.com/jfyl1573/p/6476607.html 1. LINUX网络编程基础知识 1 1.1. TCP/IP协议概述 1 1.2. OSI参考 ...

  5. Linux网络编程&内核学习

    c语言: 基础篇 1.<写给大家看的C语言书(第2版)> 原书名: Absolute Beginner's Guide to C (2nd Edition) 原出版社: Sams 作者: ...

  6. linux网络编程_1

    本文属于转载,稍有改动,以利于学习. (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个 ...

  7. Linux网络编程入门 (转载)

    (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...

  8. [转] - Linux网络编程 -- 网络知识介绍

    (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...

  9. 【转】Linux网络编程入门

    (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...

随机推荐

  1. memcache 简单入门应用

    1.memcache 简介和安装: 下载:下载文件,解压到某个地方. 2.数据存储格式 键值对,一个key对应一个值,一个值在内存中占用一个或多个4k大小的块. 3.php使用memcache的方式 ...

  2. php使用swoole实现一个简单的多人在线聊天群发

    聊天逻辑的好多细节没有实现,只实现群发. php代码: $serv = new swoole_websocket_server("127.0.0.1",3999); //服务的基本 ...

  3. delphi 基础之三 文件流操作

    文件流操作 Delphi操作流文件:什么是流?流,简单来说就是建立在面向对象基础上的一种抽象的处理数据的工具.在流中,定义了一些处理数据的基本操作,如读取数据,写入数据等,程序员是对流进行所有操作的, ...

  4. jqGrid根据ID获取行号

    根据行号获取ID $('#grid').getCell(rownumber,'id') 根据ID获取行号 $('#' + rowid)[0].rowIndex

  5. 共享内存 share pool (1):heap /extent /chunk/

    相关概念 CHUNK: Shared pool物理层面上由许多内存块组成,这些内在块称为chunk.但是chunk是大小不一的,在内存中一个chunk是连续的. EXTENT:由多个连续的chunk组 ...

  6. sqlalchemy - day4

    query 此文算是自己的一个总结,不敢说对sqlalchemy有多精通,只能算是入门的总结,免得后面忘记了这些个基本的东西.数据库的增,删,改,查,前面已经介绍了session的增,删,改,现在来介 ...

  7. the usage of key word "static" in java language

    ---恢复内容开始--- 作用 有时你希望定义一个类成员,使它的使用完全独立于该类的任何对象.通常情况下,类成员必须通过它的类的对象访问,但是可以创建这样一个成员,它能够被它自己使用,而不必引用特定的 ...

  8. Iframe 自适应高度的方法!

    第一种方法:代码简单,兼容性还可以,大家可以先测试下. function SetWinHeight(obj) { var win=obj; if (document.getElementById) { ...

  9. eclipse导出Runnable Jar File在Launch Configuration中找不到类

    1.只要选择中你需要Launch Configuration中出现的类,右击Run AS -- Java Application 再次. 2.点击导出Export的时候,就可以看到类在列表中出现了. ...

  10. [转]va_start和va_end使用详解

    转载地址:http://www.cnblogs.com/hanyonglu/archive/2011/05/07/2039916.html  本文主要介绍va_start和va_end的使用及原理. ...