[TOC]
IP和MAC地址
进入公司第一次敲代码,仅仅是一个简单练手的,就是向服务端发送客户端版本号、ip地址、mac地址。 请求配置csp文件时,链接也需要发送版本号字段(js代码-猝)。
https://zhuanlan.zhihu.com/p/93630586?from_voters_page=true
1、查看ip地址、mac地址
Windows
ipconfig
只能看见ip地址。但是使用ipconfig/all就可以看见了。
Linux
ifconfig
HWaddr和inet addr字段就是。
identification鉴定、身份证
2、inet_ntoa()
将一个32位网络字节序的二进制IP地址转换成相应的点分十进制的IP地址(返回点分十进制的字符串在静态内存中的指针)。
linux
函数声明
char *inet_ntoa(struct in_addr in);
头文件
include
所需库: winsock.h 即在程序开头写:
include
pragma comment(lib,"WS2_32.LIB")
函数原型: char FAR PASCAL FAR inet_ntoa( struct in_addr in); MSDN上本函数的原型描述为:unsigned long inet_addr( __in const char cp); in:一个表示Internet主机地址的结构。
烦:Windows和Linux不同。
3、inet_aton
inet_aton是一个计算机函数,功能是将一个字符串IP地址转换为一个32位的网络序列IP地址。如果这个函数成功,函数的返回值非零,如果输入地址不正确则会返回零。使用这个函数并没有错误码存放在errno中,所以它的值会被忽略。
头文件:#include
include
include
完整描述:
int inet_aton(const char string, struct in_addraddr);
int inet_aton(const char *cp, struct in_addr *inp);
in_addr_t inet_addr(const char *cp);
in_addr_t inet_network(const char *cp);
上面三个都可以将192.168.3.23ip地址转换成32位整数型ip,但是推荐使用inet_aton,因为另外两个无法识别255.255.255.255。http://blog.sina.com.cn/s/blog_698f90230100xwrq.html
4、大端、小端、网络字节序和主机字节序
大端(Big-Endian)就是高字节(MSB)在前,内存存储体现上,数据的高位更加靠近低地址。(低地址存高字节)
小端(Little-Endian)就是低字节(LSB)在前,内存存储体现上,数据的低位更加靠近低地址。(低地址存低字节)
网络字节序一般是指大端传输。
linux C中有个函数inet_aton可以将IPv4的字符串地址(xxx.xxx.xxx.xxx)转换成网络地址结构体 struct in_addr。
struct in_addr {
unsigned long int s_addr;
}
当通过 inet_aton转化后,返回结果中的 in_addr.s_addr 是网络字节序的。(记得要看具体的结构体) “1.2.3.4”中的最高位“1”经过inet_aton转换后出现在最低的8bit中。 在mysql中也有inet_aton这个函数,也是将字符串IPv4地址转化成整形。但是经过转换后的4位整形却是主机字节序的。和linux的库函数正好相反。
函数里面 a 代表 ascii n 代表network.第一个函数表示将a.b.c.d的IP转换为32位的IP,存储在 inp指针里面.第二个是将32位IP转换为a.b.c.d的格式.
5、uint8_t\uint_16_t\uint32_t\uint64_t
参考:浅析C语言之uint8_t / uint16_t / uint32_t /uint64_t
1、这些类型的来源:这些数据类型中都带有_t, _t 表示这些数据类型是通过typedef定义的,而不是新的数据类型。也就是说,它们其实是我们已知的类型的别名。
2、使用这些类型的原因:方便代码的维护。比如,在C中没有bool型,于是在一个软件中,一个程序员使用int,一个程序员使用short,会比较混乱。最好用一个typedef来定义一个统一的bool:typedef char bool;
在涉及到跨平台时,不同的平台会有不同的字长,所以利用预编译和typedef可以方便的维护代码。
3、这些类型的定义: 在C99标准中定义了这些数据类型,具体定义在:/usr/include/stdint.h ISO C99: 7.18 Integer types
4、格式化输出:
uint16_t %hu
uint32_t %u
uint64_t %llu
5、uint8_t类型的输出: 注意uint8_t的定义为
typedef unsigned char uint8_t;
uint8_t实际上是一个char。所以输出uint8_t类型的变量实际上输出其对应的字符,而不是数值。
6、无符号整型输出使用%u
7、c语言 编译 error: expected ';', ',' or ')' before '&' token
C语言中是不存在引用的,也就是说C语言中&表示的不是引用,仅仅是取地址符。使用指针或者改成c++。
DHCP
动态主机设置协议(英语:Dynamic Host Configuration Protocol,DHCP)是一个局域网的网络协议,使用UDP协议工作,主要有两个用途:用于内部网或网络服务供应商自动分配IP地址;给用户用于内部网管理员作为对所有计算机作中央管理的手段。
Linux下C获取所有可用网卡信息
使用ioctl函数虽然可以获取所有的信息,但是使用起来比较麻烦,如果不需要获取MAC地址,那么使用getifaddrs函数来获取更加方便与简洁。值得一提的是,在MacOS或iOS系统上(如iPhone程序开发),上述iotcl函数没法获得mac地址跟子网掩码,这个使用,使用getifaddrs函数便更有优势了。
http://blog.chinaunix.net/uid-29147497-id-4043423.html好像getifaddrs还可以获取到ipv6地址。
示例
https://blog.csdn.net/lyh2529/article/details/25957701 https://www.iteye.com/blog/naso-1815538
//必须先获得套接口清单,得到设备名,并导入进入才能获取其他的信息
//设备eth1、lo
//获取信息后保存在--.sa_data存在偏移,暂时没弄懂
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/param.h>
#include <net/if_arp.h>
#include <stdlib.h>
#include <string.h>
#define MAX_PHY_ADDR_LEN 32
int get_ip_mac_address(uint32_t &ip_addr, uint8_t mac_addr[MAX_PHY_ADDR_LEN])
{
const int MAXINTERFACE = 16;
int i, j;
char *device = "eth0";
struct ifreq ifr;
struct ifconf ifc;
struct ifreq buf[MAXINTERFACE];
int sockfd, interface_num, err;
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = (__caddr_t)buf;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
return -1;
}
err = ioctl(sockfd, SIOCGIFCONF, &ifc); // 获取所有接口信息
if (0 != err)
{
return -1;
}
interface_num = ifc.ifc_len / sizeof(struct ifreq); // 由此知存在几个设备接口
for (i = 1; i <= interface_num; i++)
{
if (0 == strcmp(device, buf[i].ifr_name)) {
strcpy(ifr.ifr_name,buf[i].ifr_name); // 必须导入设备名才能正常获取信息
err = ioctl(sockfd, SIOCGIFHWADDR, &ifr); // mac地址
if (0 == err)
{
for (j = 0; j < 6; j++)
{
mac_addr[j] = (uint8_t)ifr.ifr_hwaddr.sa_data[j];
}
}
mac_addr[6] = '0'; // 长度固定,末尾填充
mac_addr[7] = '0';
err = ioctl(sockfd, SIOCGIFADDR, &ifr); // ip地址
if (0 == err)
{
char *ip = inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr);
printf("%d\n", ((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr.s_addr);
ip_addr = ((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr.s_addr;
}
else
{
return -1;
}
}
}
close(sockfd);
return 0;
}
LOG_INFO("hj ip = %d", _local_addr.s_addr);
LOG_INFO("hj ip = %s", inet_ntoa(_local_addr));
int main()
{
uint8_t mac_addr[6];
uint32_t ip_addr;
get_ip_mac_address(ip_addr, mac_addr);
printf("ip addr: %d\n", ip_addr);
in_addr ip;
ip.s_addr = ip_addr;
printf("sddasd%s:\n", inet_ntoa(ip));
int i;
for (i = 0; i < 6; i++) printf("%02x:\n", mac_addr[i]);
return 0;
}
1、查找本机的网卡名
除了lo环回网卡之外的单网卡. 多网卡情况暂不处理,除了环回网卡lo就是网卡名。
int get_ip_mac_address(uint32_t &ip_addr, uint8_t *phy_addr, int phy_addr_len)
{
ASSERT(NULL != phy_addr);
int ret, sockfd, err;
struct ifreq ifr;
struct ifaddrs *ifaddr, *ifa;
std::string netName;
ret = getifaddrs(&ifaddr);
if(ret < 0) {
LOG_ERROR("Get ifaddrs is failed(%d)", ret);
return -1;
}
//获取除了lo环回网卡之外的单网卡. 多网卡情况暂不处理
for(ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if(strncmp(ifa->ifa_name, LO_NET_NAME, strlen(LO_NET_NAME))) {
netName = ifa->ifa_name;
}
}
LOG_INFO("Eth name is :[ %s ]", netName.c_str());
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, netName.c_str(), sizeof(ifr.ifr_name) - 1);
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
LOG_ERROR("Open socket error, %d, %s", errno, strerror(errno));
return -1;
}
err = ioctl(sockfd, SIOCGIFADDR, &ifr); // ip地址
if (0 == err) {
ip_addr = ((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr.s_addr;
}
else {
LOG_ERROR("Get ip address fail, %d, %s", errno, strerror(errno));
goto FAIL;
}
memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
err = ioctl(sockfd, SIOCGIFHWADDR, &ifr); // mac地址
if (0 == err) {
if (phy_addr_len < PHY_ADDR_LEN || sizeof(ifr.ifr_hwaddr.sa_data) < PHY_ADDR_LEN) {
LOG_ERROR("Mac address format error.");
goto FAIL;
}
memcpy(phy_addr, ifr.ifr_hwaddr.sa_data, PHY_ADDR_LEN);
}
else {
LOG_ERROR("Get mac address fail, %d, %s", errno, strerror(errno));
goto FAIL;
}
freeifaddrs(ifaddr);
close(sockfd);
return 0;
FAIL:
freeifaddrs(ifaddr);
close(sockfd);
return -1;
}
7、IP地址
7-1、IP地址的表示法
1、ASCII表示法: 210.25.132.181,也就是字符串形式,英语叫做IPv4 numbers-and-dots notation。
2、整型表示法: 3524887733,整数形式的IP地址,。英语叫做binary data。
7-2、IP地址的转换
IPv4: 1、inet_addr函数
include
in_addr_t inet_addr(const char* strptr);
将字符串转换为32位二进制网络字节序的IPV4地址,即将一个点间隔地址转换成一个in_addr。
2、inet_ntoa函数
include
char* inet_ntoa(struct in_addr in);
将一个十进制网络字节序转换为点分十进制IP格式的字符串。
3、 inet_ntoa函数
include
int inet_aton(const char string, struct in_addr addr);
是一个改进的方法来将一个字符串IP地址转换为一个32位的网络序列IP地址。
IPv6 : 1、inet_pton函数
2、inet_ntop函数
程序示例:
Include
include
include
strcut sockaddr_in src;
src.sin_addr.s_addr = inet_addr("..."); //构建网络地址。
printf("%s\n",inet_ntoa(src.sin_addr)); //将网络地址转换成字符串。
in_addr_in inet_addr(const char *strptr);
inet_addr的参数是一个:点分十进制字符串,返回的值为一个32位的二进制网络字节序的IPv4地址,不然的话就是:INADDR_NONE
而返回值为:in_addr_t:IPv4,一般为uint32_t
所以也可以定义为:unsigned long
char * inet_ntoa(struct in_addr inaddr);
参数是一个结构体,所以要调用必须先定义一个结构体。