`
hulianwang2014
  • 浏览: 686608 次
文章分类
社区版块
存档分类
最新评论
  • bcworld: 排版成这样,一点看的欲望都没有了
    jfinal

socket 套接字编程笔记——IP地址转换

 
阅读更多


0.前言

网上有很多使用arduion和树莓派连接yeelink的例子,硬件和软件的实现方式都非常简单。通过学习这些例子一下激发我学习嵌入式网络的动力。虽然使用arduion连接yeelink简单方便稳定可靠,但是依然像使用嵌入式以太网协议栈连接yeelink,例如MCU使用STM32,网卡芯片使用ENC28J60,以太网协议栈使用LwIP。虽然这样做硬件软件都要复杂的多,但是也多了不少“乐趣”。事情总是要循序渐进,我决定先认真研究socket编程,使用PC平台和yeelink交换数据。

1.测试环境说明

windows环境,编译器为minGW,IDE为eclipse。windows环境下的套接字编程和linux环境略有区别,但是基本的思路和方法相同。若使用minGW加eclipse的开发方式,需要加入wsock32库。添加的方法如下:
1.project -> properties
2.c/c++ build -> settting
3.tool setting -> mingw c linker -> libraries
4.add wsock32

图1 添加wsock32库

2.IP地址格式转换

通常情况下,IP地址都被写成以下格式:192.168.1.101或者10.13.11.105。这种形式的IP地址易于理解,但是对于协议处理来说就显得不是那么的方便,为了让IP地址更容易被处理并兼顾网络传输中的格式(网络传输为大端格式),所以定义了in_addr结构体:
struct in_addr {
	union {
		struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
		struct { u_short s_w1,s_w2; } S_un_w;
		u_long S_addr;
	} S_un;
#define s_addr  S_un.S_addr
#define s_host  S_un.S_un_b.s_b2
#define s_net   S_un.S_un_b.s_b1
#define s_imp   S_un.S_un_w.s_w2
#define s_impno S_un.S_un_b.s_b4
#define s_lh    S_un.S_un_b.s_b3
};

在一些网上流传的套接字代码中,经常会看到这样的代码
struct in_addr server_addr
server_addr.s_addr = .....
此处的server_addr为一个in_addr类型结构体,server_addr代表一个IP地址。如果理解in_addr类型结构体,也就是把一个IP地址理解为4个字符,或2个16位长度整数,或1个32位长度的整数。由于in_addr类型结构体中包含一个共用体。为使编程更简便些可使用s_addr替代S_un.S_addr,所以便有了server_addr.s_addr这样的代码。in_addr类型结构体一般不单独出现(除了DNS地址解析外),而是存在于sockaddr_in结构体中,sockaddr_in可理解为套接字地址结构体。

3.格式之间的相互转换

ASCII形式的IP地址可以和整数形式的IP地址相互相关,在windows平台下可以使用inet_addr和inet_ntoa。

3.1 inet_addr

函数原型和输入输出参数
unsigned long inet_addr(
  _In_  const char *cp
);
函数作用
把ASCII格式的IP地址(AAA.BBB.CCC.DDD形式)转换为一个32位无符号整数。

3.2inet_ntoa

函数原型和输入输出参数
char* FAR inet_ntoa(
  _In_  struct   in_addr in
);
函数作用
把in_addr类型的IP地址转换为ASCII格式的IP地址(AAA.BBB.CCC.DDD形式)。inet_ntoa中的n可理解为network,a可理解为ascii。该函数一般用于打印IP地址。

4.示例代码

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>

int main(int argc, char **argv)
{
    unsigned long addr = INADDR_NONE;

    // 测试inet_addr
    char server_ipaddr[] = {"192.168.1.101"};
    addr = inet_addr( server_ipaddr);
    if ( addr == INADDR_NONE && addr == INADDR_ANY )
    {
        printf("转换失败\n");
        return 1;
    }   
    // 转换结果(unsigned long)1694607552
    printf("转换结果(unsigned long)%lu\n",addr);

    // 测试inet_itoa
    // 转化为ASCII字符串形式的IP地址
    struct in_addr client_ipaddr;
    client_ipaddr.s_addr = addr;

    // 转换结果("XXX.XXX.XXX.XXX") 192.168.1.101
    printf( "转换结果(\"XXX.XXX.XXX.XXX\") %s" , inet_ntoa( client_ipaddr ) );

    return 0;
}

运行结果
转换结果(unsigned long)1694607552
转换结果("XXX.XXX.XXX.XXX") 192.168.1.101

程序分析
首先准备一个ASCII形式的IP地址,例如192.168.1.101。使用inet_addr转换为一个32位无符号整数,转换结果为1694607552。保留该结果并在通过inet_ntoa还原192.168.1.101。还原之前需要先定义in_addr类型结构体,并命名为client_ipaddr,client_ipaddr.s_addr为32位无符号整数可直接赋值。最后使用inet_ntoa对client_ipaddr变量进行格式转换并通过串口打印。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics