加入星計劃,您可以享受以下權益:

  • 創(chuàng)作內容快速變現(xiàn)
  • 行業(yè)影響力擴散
  • 作品版權保護
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • 從配置文件中讀取IP地址
    • 自動獲取IP地址
  • 相關推薦
  • 電子產業(yè)圖譜
申請入駐 產業(yè)圖譜

嵌入式開發(fā)小記,實用小知識分享

2021/10/06
317
閱讀需 9 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

之前為了方便測試部門保存一些測試數(shù)據(jù),需要臨時開發(fā)一個簡單的nanomsg server,與板子端的client在局域網內進行通信,接收client數(shù)據(jù)并保存。關于nanomsg的簡單使用介紹可查看往期文章:一個實用通信庫的簡單使用分享

作為server端,需要綁定電腦的IP,不同的電腦IP是不一樣的,所以使用不同的電腦時需要修改IP才能正常使用這個server程序。

在不需要重新編譯程序的情況下,有如下兩種方法可以滿足這個需求:

  • 把IP寫在配置文件里,比如ini格式的配置文件里,然后server程序讀取配置文件里的IP,再進行綁定。server程序自動獲取IP地址并綁定。

下面分別使用這兩種方法:

從配置文件中讀取IP地址

配置文件的格式有很多,如JSON、INI等。這里我選用的是INI格式的配置文件,.ini 文件是 Initialization File 的縮寫,即初始化文件。INI文件由節(jié)、鍵、值組成,注解使用分號表示(;)。例如:

[Section1 Name]
KeyName1_1=value1_1  ;這是注釋
KeyName1_2=value1_2
[Section2 Name]
KeyName2_1=value2_1
KeyName2_2=value2_2

這里我們使用inih解析器來對INI文件進行解析。

inih:一個C 語言編寫的 INI 文件解析器。

inih解析器的地址:

https://github.com/benhoyt/inih

同時,inih解析器也已經被收錄于大雜燴資源匯總貼中:

https://gitee.com/zhengnianli/EmbedSummary

inih的使用很簡單,下面一起來看一下。

下載得到的inih內容如圖所示:

 

ini.cini.h 放到我們的工程下即可。這里我們使用一個測試工程:

 

同時,新建一個 ip.ini 文件存放于工程目錄下。ip.ini 文件的內容如:

[ip]                ;Section1
ip_addr = 192.168.1.103

[test]              ;Section2
name = ZhengN       
num  = 66

下面我們編寫代碼test.c來解析這個文件:

// 微信公眾號:嵌入式大雜燴
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ini.h"

typedef struct
{
    const char* ip_addr;
    const char* name;
    int num;
} configuration;

static int handler(void* user, const char* section, const char* name,
                   const char* value)
{
    configuration* pconfig = (configuration*)user;

    #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
    if (MATCH("ip", "ip_addr")) 
    {
        pconfig->ip_addr = strdup(value);
    } 
    else if (MATCH("test", "name")) 
    {
        pconfig->name = strdup(value);
    } 
    else if (MATCH("test", "num")) 
    {
        pconfig->num = atoi(value);
    } 
    else 
    {
        return 0;  /* unknown section/name, error */
    }

    return 1;
}

int main(int argc, char* argv[])
{
    configuration config;
    config.ip_addr = NULL;  /* set defaults */
    config.name = NULL;
    config.num = 0;

    if (ini_parse("ip.ini", handler, &config) < 0) 
    {
        printf("Can't load 'ip.ini'n");
        return 1;
    }
    printf("Config loaded from 'ip.ini': ip_addr = %s, name = %s, num = %dn",
        config.ip_addr, config.name, config.num);

    if (config.ip_addr)
        free((void*)config.ip_addr);
    if (config.name)
        free((void*)config.name);

    return 0;
}

解析方法很簡單(可參考 inih/examples 下的demo,我們這里也是模仿這個demo來做解析的):

構造一個配置結構體 configuration ,定義一個configuration結構體用于保存我們解析的數(shù)據(jù),結構體里面的成員就是我們需要解析的INI文件里的各個鍵。例如,我們的ip.ini文件里有ip_addr、name、num這三個鍵,結構體里的成員表示的就是這三個鍵。

定義一個handler回調函數(shù),用于處理解析過程。解析過程也很簡單,匹配Section Name及Key Name,然后取出值即可。

調用 ini_parse 函數(shù)對INI文件進行解析。

其中,handler函數(shù)里調用了一個 strdup() 函數(shù)及 atoi() 函數(shù)。

  • strdup()函數(shù)是c語言中常用的一種字符串拷貝庫函數(shù),一般和free()函數(shù)成對出現(xiàn),,因為strdup()在內部調用了malloc()函數(shù)為變量分配內存。atoi()函數(shù)(ascii to integer)是把字符串轉換成整型數(shù)的一個函數(shù)。

編譯、運行:

 

自動獲取IP地址

我們可以使用 getifaddrs() 函數(shù)來獲取。getifaddrs()函數(shù)用于獲取網卡信息,包括IP、掩碼、廣播地址等信息。

getifaddrs()函數(shù)原型:

int getifaddrs (struct ifaddrs **__ifap);
  • __ifap為獲取得到的網卡信息。

用getifaddrs()函數(shù)獲取得到的IP格式為 數(shù)值格式(numeric),需要轉成 表達格式(presentation)。inet_ntop() 函數(shù)可以滿足這個需求。

inet_ntop()函數(shù)是隨IPv6出現(xiàn)的函數(shù),對于IPv4地址和IPv6地址都適用,函數(shù)中p和n分別代表 表達格式(presentation)數(shù)值格式(numeric) 。IP地址的表達格式是ASCII字符串,數(shù)值格式則是存放到套接字地址結構的二進制值。我們這里需要的就是ASCII字符串形式的IP地址。

inet_ntop()函數(shù)原型:

const char * inet_ntop(int family, const void *addrptr, char *strptr, size_t len);

family參數(shù):既可以是AF_INET(ipv4)也可以是AF_INET6(ipv6)。

addrptr參數(shù):addrptr指針指向數(shù)值格式的IP。

strptr參數(shù):strptr指向表達格式的IP,調用者必須為目標存儲單元分配內存并指定其大小。

len參數(shù):容納表達格式的長度。

返回值:若成功則為指向表達格式的指針,若出錯則為NULL。

下面看看實例代碼:

// 微信公眾號:嵌入式大雜燴
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ifaddrs.h>
#include <arpa/inet.h>

char *get_ip_addr(void)
{
 static char ip_str[256] = {0};
 struct ifaddrs *ifaddrs_struct = NULL;
 void *addrptr = NULL;
 
 if (getifaddrs(&ifaddrs_struct) != 0)
 {
  printf("getifaddrs error!n");
  return NULL;
 }
 
 struct ifaddrs *tmp_ifaddrs = ifaddrs_struct;
 while (tmp_ifaddrs != NULL)
 {
        // IPv4
  if (tmp_ifaddrs->ifa_addr->sa_family == AF_INET)
  {
            #define INET_ADDR_STR_LEN  256
   char addr_buf[INET_ADDR_STR_LEN];
   addrptr = &((struct sockaddr_in*)tmp_ifaddrs->ifa_addr)->sin_addr;
   if (inet_ntop(AF_INET, addrptr, addr_buf, INET_ADDR_STR_LEN) == NULL)
   {
    printf("inet_ntop error!n");
    return NULL;
   }
            if (strlen(addr_buf) < sizeof(ip_str) - strlen(ip_str))
            {
                strncat(ip_str, addr_buf, strlen(addr_buf));
                strncat(ip_str, ";", strlen(";"));
            }
   
  }
        // IPv6
        else if (tmp_ifaddrs->ifa_addr->sa_family == AF_INET6)
        {
            
        }
  
  tmp_ifaddrs = tmp_ifaddrs->ifa_next;
 }
 
 freeifaddrs(ifaddrs_struct);

    return ip_str;
}

int main(int argc, char** argv)
{
    printf("hello world!n");
    char *ip_addr = get_ip_addr();
    printf("ip addr : %sn", ip_addr);

    return 0;
}

編譯、運行:

 

 

相關推薦

電子產業(yè)圖譜

本公眾號專注于嵌入式技術,包括但不限于C/C++、嵌入式、物聯(lián)網、Linux等編程學習筆記,同時,公眾號內包含大量的學習資源。歡迎關注,一同交流學習,共同進步!