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

来源:互联网 发布:传奇归来网络传输异常 编辑:程序博客网 时间:2024/06/05 07:18


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.2 inet_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变量进行格式转换并通过串口打印。

原创粉丝点击