前面写了一篇关于网络相关的文章:如何获取当前可用网口。

《简简单单教你如何用C语言列举当前所有网口!》

那么如何使用C语言直接操作网口?

比如读写IP地址、读写MAC地址等。

一、原理

主要通过系统用socket()、ioctl()、实现

int socket(int domain, int type, int protocol);
功能:
创建套接字
参数:
domain:
Name Purpose Man page
AF_UNIX, AF_LOCAL Local communication unix(7)
AF_INET IPv4 Internet protocols ip(7) type:
SOCK_STREAM Provides sequenced, reliable, two-way, connection-based
byte streams. An out-of-band data transmission mecha‐
nism may be supported.
SOCK_DGRAM Supports datagrams (connectionless, unreliable messages
of a fixed maximum length).
protocol:
通常为0
返回值:
成功:新的套接字的文件描述符
失败:错误码,负值
int ioctl(int fd, unsigned long request, ...);
参数:
fd :文件描述符
request:命令
... :参数

其中网络用到的request定义头文件位于:

/usr/include/linux/sockios.h
/* Linux-specific socket ioctls */
#define SIOCINQ FIONREAD
#define SIOCOUTQ TIOCOUTQ /* output queue size (not sent + not acked) */ /* Routing table calls. */
#define SIOCADDRT 0x890B /* add routing table entry */
#define SIOCDELRT 0x890C /* delete routing table entry */
#define SIOCRTMSG 0x890D /* call to routing system */ /* Socket configuration controls. */
#define SIOCGIFNAME 0x8910 /* get iface name */
#define SIOCSIFLINK 0x8911 /* set iface channel */
#define SIOCGIFCONF 0x8912 /* get iface list */
#define SIOCGIFFLAGS 0x8913 /* get flags */
#define SIOCSIFFLAGS 0x8914 /* set flags */
#define SIOCGIFADDR 0x8915 /* get PA address */
#define SIOCSIFADDR 0x8916 /* set PA address */
#define SIOCGIFDSTADDR 0x8917 /* get remote PA address */
#define SIOCSIFDSTADDR 0x8918 /* set remote PA address */
#define SIOCGIFBRDADDR 0x8919 /* get broadcast PA address */
#define SIOCSIFBRDADDR 0x891a /* set broadcast PA address */
#define SIOCGIFNETMASK 0x891b /* get network PA mask */
#define SIOCSIFNETMASK 0x891c /* set network PA mask */
#define SIOCGIFMETRIC 0x891d /* get metric */
#define SIOCSIFMETRIC 0x891e /* set metric */
#define SIOCGIFMEM 0x891f /* get memory address (BSD) */
#define SIOCSIFMEM 0x8920 /* set memory address (BSD) */
#define SIOCGIFMTU 0x8921 /* get MTU size */
#define SIOCSIFMTU 0x8922 /* set MTU size */
#define SIOCSIFNAME 0x8923 /* set interface name */
#define SIOCSIFHWADDR 0x8924 /* set hardware address */
#define SIOCGIFENCAP 0x8925 /* get/set encapsulations */
#define SIOCSIFENCAP 0x8926
#define SIOCGIFHWADDR 0x8927 /* Get hardware address */
#define SIOCGIFSLAVE 0x8929 /* Driver slaving support */
#define SIOCSIFSLAVE 0x8930
#define SIOCADDMULTI 0x8931 /* Multicast address lists */
#define SIOCDELMULTI 0x8932
#define SIOCGIFINDEX 0x8933 /* name -> if_index mapping */
#define SIOGIFINDEX SIOCGIFINDEX /* misprint compatibility :-) */
#define SIOCSIFPFLAGS 0x8934 /* set/get extended flags set */
#define SIOCGIFPFLAGS 0x8935
#define SIOCDIFADDR 0x8936 /* delete PA address */
#define SIOCSIFHWBROADCAST 0x8937 /* set hardware broadcast addr */
#define SIOCGIFCOUNT 0x8938 /* get number of devices */
……

其中ioctl的参数需要借助结构体struct ifreq

定义头文件:

/usr/include/linux/if.h
#if __UAPI_DEF_IF_IFREQ
struct ifreq {
#define IFHWADDRLEN 6
union
{
char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */
} ifr_ifrn; union {
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
struct sockaddr ifru_netmask;
struct sockaddr ifru_hwaddr;
short ifru_flags;
int ifru_ivalue;
int ifru_mtu;
struct ifmap ifru_map;
char ifru_slave[IFNAMSIZ]; /* Just fits the size */
char ifru_newname[IFNAMSIZ];
void * ifru_data;
struct if_settings ifru_settings;
} ifr_ifru;
};
#endif /* __UAPI_DEF_IF_IFREQ */ #define ifr_name ifr_ifrn.ifrn_name /* interface name */
#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */
#define ifr_addr ifr_ifru.ifru_addr /* address */
#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */
#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */
#define ifr_flags ifr_ifru.ifru_flags /* flags */
#define ifr_metric ifr_ifru.ifru_ivalue /* metric */
#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
#define ifr_map ifr_ifru.ifru_map /* device map */
#define ifr_slave ifr_ifru.ifru_slave /* slave device */
#define ifr_data ifr_ifru.ifru_data /* for use by interface */
#define ifr_ifindex ifr_ifru.ifru_ivalue /* interface index */
#define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */
#define ifr_qlen ifr_ifru.ifru_ivalue /* Queue length */
#define ifr_newname ifr_ifru.ifru_newname /* New name */
#define ifr_settings ifr_ifru.ifru_settings /* Device/proto settings*/

二、函数实现

下面将实现不同功能的函数一一列举。

0. 列出所有可用网口

int list_all_port()
{
struct ifconf ifconf;
struct ifreq *ifr;
int m, n, s, fd; if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
return -11;
} s = sizeof(struct ifreq)*5;
for (;;) {
ifr = malloc(s); ifconf.ifc_len = s;
ifconf.ifc_req = ifr; if (ioctl(fd, SIOCGIFCONF, &ifconf) < 0) {
perror("SIOCGIFCONF:");
free(ifr);
close(fd);
return 1;
} if (ifconf.ifc_len != s)
break; free(ifr);
s *= 2;
} close(fd); m = ifconf.ifc_len/sizeof(struct ifreq);
for (n = 0; n < m; n++)
{
printf("port:\t%s\n",ifconf.ifc_req[n].ifr_name);
}
free(ifr);
}

1. 获取指定网卡IP

int getLocalIp(const char *eth, char *ip) {
struct ifreq ifr;
struct sockaddr_in sin;
int fd;
bzero(&ifr, sizeof(ifr));
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
return -1;
}
strcpy(ifr.ifr_name, eth);
if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
close(fd);
return -1;
}
memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
snprintf(ip, IP_SIZE, "%s", inet_ntoa(sin.sin_addr));
close(fd);
return 0;
}

2. 设置本网卡IP地址

int setIpAddrManual(const char *eth, char *ipstr) {
int fd;
struct sockaddr_in sin;
struct ifreq ifr;
bzero(&ifr, sizeof(ifr));
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
return -1;
}
strcpy(ifr.ifr_name, eth); sin.sin_addr.s_addr = inet_addr(ipstr); sin.sin_family = AF_INET;
memcpy(&ifr.ifr_addr, &sin, sizeof(sin)); if (ioctl(fd, SIOCSIFADDR, &ifr) < 0)
{
perror("");
close(fd);
return -1;
}
close(fd);
return 0;
}

3. 获取本机网卡Mac地址

int getLocalMac(const char *eth, char *mac) {

    int fd;
struct ifreq ifr;
bzero(&ifr, sizeof(ifr));
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
return -1;
}
strcpy(ifr.ifr_name, eth);
if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0)
{
close(fd);
return -1;
}
snprintf(mac,18, "%02x:%02x:%02x:%02x:%02x:%02x",
(unsigned char) ifr.ifr_hwaddr.sa_data[0],
(unsigned char) ifr.ifr_hwaddr.sa_data[1],
(unsigned char) ifr.ifr_hwaddr.sa_data[2],
(unsigned char) ifr.ifr_hwaddr.sa_data[3],
(unsigned char) ifr.ifr_hwaddr.sa_data[4],
(unsigned char) ifr.ifr_hwaddr.sa_data[5]);
close(fd);
return 0; }

4. 设置网卡mac地址

/*
support format [00:11:22:33:44:55]
*/
#define MAC_ARRAY(mac_array) (unsigned int *)&mac_array[0],(unsigned int *)&mac_array[1],(unsigned int *)&mac_array[2],(unsigned int *)&mac_array[3],(unsigned int *)&mac_array[4],(unsigned int *)&mac_array[5]
int setLocalMac(const char *eth, char *mac) {
int fd;
struct ifreq ifr;
unsigned char mac_array[6] = {0}; bzero(&ifr, sizeof(ifr));
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
return -1;
}
strcpy(ifr.ifr_name, eth);
ifr.ifr_hwaddr.sa_family = AF_LOCAL; sscanf(mac,"%02x:%02x:%02x:%02x:%02x:%02x",
MAC_ARRAY(mac_array)); memcpy(ifr.ifr_hwaddr.sa_data,mac_array,6); if (ioctl(fd, SIOCSIFHWADDR, &ifr) < 0)
{
perror("SIOCSIFHWADDR:");
close(fd);
return -1;
} close(fd);
return 0;
}

注意:

  • 网卡地址的第一字节必须是偶数
  • sa_family 值必须为:AF_LOCAL

5. 获取网卡mtu

int getMtu(const char *eth, char *mtu) {
int fd;
struct ifreq ifr;
bzero(&ifr, sizeof(ifr));
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
return -1;
}
strcpy(ifr.ifr_name, eth);
if (ioctl(fd, SIOCGIFMTU, &ifr) < 0)
{
close(fd);
return -1;
}
snprintf(mtu,64, "%d", (unsigned char) ifr.ifr_mtu);
close(fd);
return 0;
}

6. 获取广播地址

int getBroadAddr(const char *eth, char *ip) {
int fd;
struct sockaddr_in sin;
struct ifreq ifr;
bzero(&ifr, sizeof(ifr));
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
return -1;
}
strcpy(ifr.ifr_name, eth);
if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
{
perror("");
close(fd);
return -1;
}
memcpy(&sin, &ifr.ifr_broadaddr, sizeof(sin));
snprintf(ip, IP_SIZE, "%s", inet_ntoa(sin.sin_addr)); close(fd);
return 0;
}

7. 获取掩码

int getNetMask(const char *eth, char *mask) {
int fd;
struct sockaddr_in sin;
struct ifreq ifr;
bzero(&ifr, sizeof(ifr));
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
return -1;
}
strcpy(ifr.ifr_name, eth);
if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
{
perror("");
close(fd);
return -1;
}
memcpy(&sin, &ifr.ifr_netmask, sizeof(sin));
snprintf(mask, IP_SIZE, "%s", inet_ntoa(sin.sin_addr)); close(fd);
return 0;
}

8. 获取网卡flag

int getFlags(const char *eth, char *fg) {
int fd;
struct sockaddr_in sin;
struct ifreq ifr;
bzero(&ifr, sizeof(ifr));
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
return -1;
}
strcpy(ifr.ifr_name, eth);
if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0)
{
perror("");
close(fd);
return -1;
}
snprintf(fg, IP_SIZE, "%x", ifr.ifr_flags); close(fd);
return 0;
}

三、测试

1. 测试程序

int main(int argc, char **argv)
{
int fg=0;
char mac[32]={};
char ip[IP_SIZE]={0};
char buf[64]; getBroadAddr(ethname,ip);
printf("broad ip:\t%s\n",ip); getNetMask(ethname,ip);
printf("mask:\t%s\n",ip); setIpAddrManual(ethname, "1.1.1.1");
getLocalIp(ethname,ip);
printf("ip:\t%s\n",ip); setLocalMac(ethname,"00:11:22:33:44:55");
getLocalMac(ethname,mac);
printf("mac:\t%s\n",mac); getMtu(ethname,buf);
printf("mtu:\t%s\n",buf); return 1;
}

2. 执行结果

执行后结果:

peng@ubuntu:~/work/test/ip$ ifconfig
eth0 Link encap:Ethernet HWaddr 00:11:22:33:44:55
inet addr:1.1.1.1 Bcast:1.255.255.255 Mask:255.0.0.0
inet6 addr: fe80::d9d4:d42b:a04a:9d40/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:188577 errors:0 dropped:0 overruns:0 frame:0
TX packets:208116 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:53762370 (53.7 MB) TX bytes:172094089 (172.0 MB)

完整代码获取,请点赞转发,并后台留言:eth

Linux下C语言操作网卡的几个代码实例?特别实用的更多相关文章

  1. Linux下C语言操作MySQL数据库

    MySQL是Linux系统下广泛使用的开源免费数据库,是Linux应用程序数据存储的首选. Ubuntu下安装 […]

  2. Linux下C语言RPC(远程过程调用)编程实例

    在查看libc6-dev软件包提供的工具(用 dpkg -L libc6-dev 命令)的时候,发现此软件包提供了一个有用的工具rpcgen命令.通过rpcgen的man手册看到此工具的作用是把RPC ...

  3. linux 下C语言学习路线

    UNIX/Linux下C语言的学习路线.一.工具篇“公欲善其事,必先利其器”.编程是一门实践性很强的工作,在你以后的学习或工作中,你将常常会与以下工具打交道, 下面列出学习C语言编程常常用到的软件和工 ...

  4. Linux下C语言编程实现spwd函数

    Linux下C语言编程实现spwd函数 介绍 spwd函数 功能:显示当前目录路径 实现:通过编译执行该代码,可在终端中输出当前路径 代码实现 代码链接 代码托管链接:spwd.c 所需结构体.函数. ...

  5. Unix和Linux下C语言学习指南

    转自:http://www.linuxdiyf.com/viewarticle.php?id=174074 Unix和Linux下C语言学习指南 引言 尽管 C 语言问世已近 30 年,但它的魅力仍未 ...

  6. 笔记整理——Linux下C语言正则表达式

    Linux下C语言正则表达式使用详解 - Google Chrome (2013/5/2 16:40:37) Linux下C语言正则表达式使用详解 2012年6月6日Neal627 views发表评论 ...

  7. linux下C语言多线程编程实例

    用一个实例.来学习linux下C语言多线程编程实例. 代码目的:通过创建两个线程来实现对一个数的递加.代码: //包含的头文件 #include <pthread.h> #include ...

  8. 20155322 2017-2018-1《信息安全系统设计》第二周 课堂测试 Linux下C语言实现MYOD

    20155322 2017-2018-1<信息安全系统设计>第二周 课堂测试 Linux下C语言实现MYOD [博客目录] 静态库测试 实现方法 相关资料 操作 动态库测试 实现方法 相关 ...

  9. Linux基础与Linux下C语言编程基础

    Linux基础 1 Linux命令 如果使用GUI,Linux和Windows没有什么区别.Linux学习应用的一个特点是通过命令行进行使用. 登录Linux后,我们就可以在#或$符后面去输入命令,有 ...

  10. LINUX下C语言编程基础

    实验二 Linux下C语言编程基础 一.实验目的 1. 熟悉Linux系统下的开发环境 2. 熟悉vi的基本操作 3. 熟悉gcc编译器的基本原理 4. 熟练使用gcc编译器的常用选项 5 .熟练使用 ...

随机推荐

  1. 2024-06-26:用go语言,给定一个长度为n的数组nums和一个正整数k, 找到数组中所有相差绝对值恰好为k的子数组, 并返回这些子数组中元素之和的最大值。 如果找不到这样的子数组,返回0。 输

    2024-06-26:用go语言,给定一个长度为n的数组nums和一个正整数k, 找到数组中所有相差绝对值恰好为k的子数组, 并返回这些子数组中元素之和的最大值. 如果找不到这样的子数组,返回0. 输 ...

  2. ClickHouse介绍(二)MergeTree引擎

    MergeTree引擎 ClickHouse中有多种表引擎,包括MergeTree.外部存储.内存.文件.接口等,6大类,20多种表引擎.其中最强大的当属MergeTree(及其同一家族中)引擎.我们 ...

  3. 信奥一本通1164:digit函数

    1164:digit函数 时间限制: 1000 ms 内存限制: 65536 KB 提交数:41504 通过数: 26475 [题目描述] 在程序中定义一函数digit(n,k) ,它能分离出整数n ...

  4. 【WPF】根据选项值显示不同的编辑控件(使用DataTemplateSelector)

    接了一个小杂毛项目,大概情形是这样的:ZWT先生开的店是卖拆片机的,Z先生不仅卖机器,还贴心地提供一项服务:可以根据顾客需要修改两个电机的转向和转速(机器厂家有给SDK的,但Z自己不会写程序).厂家有 ...

  5. python 无监督生成模型

    无监督生成模型在机器学习中扮演着重要角色,特别是当我们在没有标签数据的情况下想要生成新的样本或理解数据的内在结构时.一种流行的无监督生成模型是生成对抗网络(Generative Adversarial ...

  6. linux 清理 pyinstaller 打包程序运行留下的临时文件

    前言 pyinstaller 打包的 python 二进制可执行程序运行的时候,会在 /tmp 目录下生成 _MEI* (*指的是随机数字)文件夹, 如果程序没有正常退出或者终止了,_MEI* 文件夹 ...

  7. 1.Javascript 快速入门(主要)

    运算 &&运算是与运算,只有所有都为true,&&运算结果才是true: true && true; // 这个&&语句计算结果为tru ...

  8. Linux 更新网络时间

    下载包 yum install -y ntpdate 同步网络时间 ntpdate 0.asia.pool.ntp.org 若上面的时间服务器不可用,也可以改用如下服务器进行同步: time.nist ...

  9. FPGA bit转bin文件

    首先科普一下 什么是bitstream文件 FPGA比特流(bitstream)是一种用于配置可编程逻辑器件的数据格式,特别是现场可编程门阵列(FPGA).比特流包含了硬件逻辑电路.路由信息以及芯片上 ...

  10. git 怎么将某个开发分支最近几次的提交合并成一次提交

    1. 切换到开发分支: git checkout dev 2. 运行交互式 rebase 命令,并指定要合并的提交数量(在这个例子中是最近的3次提交): git rebase -i HEAD~3 3. ...