admin 管理员组

文章数量: 887018

六十四、网络编程基础

1. 网络基础

1.1 网络编程的概念

  1. 网络编程就是进程间通信,只不过多个进程间不一定在同一台主机上。
  2. 由于不在同一个主机上,不在同一个进程上就需要注意协议

1.2 联网协议和层

  • 联网协议:定义如何在一个网络上传输信息的一组规则

1.2.1 网络采用分层的思想

  1. 在计算机网络体系中,采用层次化的思想,将通信协议中必要的功能进行分层。
  2. 每一层都接收由它下一层所提供的特定服务,并且负责为自己的上一层提供特定的服务。
  3. 上下层之间进行交互所遵循的约定叫做『接口』。
  4. 同一层之间进行交互所遵循的约定叫做『协议』。
  5. 『接口』 即相邻两层之间交换位置的连接点,是上层使用下层服务的入口。
  6. 『协议』 即通信双方所做的一些约定,比如怎么开始通信、信息的格式与顺序、怎么结束通信等。
  • 分层的好处:
  1. 各层之间独立,每一层不需要知道下一层如何实现,而仅仅只需要知道该层通过层间的接口所提供的的服务。
  2. 稳定,当任何一层发生变化时,只要层间接口关系保持不变,则这层以上或以下层不受影响。
  3. 易于实现和维护(知道是什么功能,就到指定层去查找)
  4. 促进标准化工作

1.2.2 OSI体系结构(重点!!)

  • ISO(国际标准化组织)制定了一个国际标准OSI(开放式通讯系统互联参考模型),对通讯系统进行了标准化。
  • 定义了7层模型


    顺口溜:(虽然貌似有点不顺)
    屋里(物理)数据要跑路,沿着链路上高速。—>物理层,数据链路层
    跑到高速没网络,数据传输靠不住。—>网络层,传输层
    掏出手机要叫人,一开会话嘟嘟嘟。—>会话层
    老铁表示要玩完,应用技术才懂路。—>表示层、应用层

1.2.3 TCP/IP协议介绍

  • OSI模型是一个理想化的模型已经很少使用,没有完整的实现,但是模型本身非常通用。
  • TCP/IP协议 是Internet事实上的工业标准

(1) 网络接口与物理层 也叫做网络访问层
  • 功能:包括ip地址与物理地址的映射(MAC),以及将上一层的ip报文封装层帧,转换成二进制比特流传输
  • MAC:物理地址,48bit全球唯一,网卡编号,网络设备的身份标识(cmd —>ipconfig/all),由厂商出厂后确定。
  • 改变网络环境后,IP地址变,MAC地址不变
  • 由电气电子工程协会IEEE定义。

部分协议举例:

  • ARP/RARP 地址解析协议/逆向地址解析协议
  • ARP(Address Resolution Protocol):通过ip地址获取其对应的mac地址。
  • RARP(Reverse Address Resolution Protocol):通过mac地址获取其对应的ip地址。
  • PPP(Point to Point Protocol)协议:拨号协议(GPRS/3G/4G)

MTU:最大传输单元:1500bytes
MSS:最大报文长度:1460bytes

(2) 网络层
  • 负责在主机之间的通讯中选择数据包传输的路径,即选择路由。

① IP协议(Internet Protocol)

  • ip协议根据数据包的目的ip地址来决定如何投递数据包。
  • 如果数据包不能直接投递给目标主机,那么ip协议就为他寻找下一个合适的下一跳路由器。
  • 路由器就是工作在网络层

② ICMP协议(Internet Control Management Protocol)

  • 英特网控制管理协议,ping检测网络就是用这个协议
  • 用于在IP主机、路由器之间传递控制消息
  • ping 命令 使用的就是这个协议

③ IGMP协议(Internet Group Management Protocol)

  • 英特网分组管理协议,组播,广播。
(3) 传输层(重点!)
  • 负责提供应用程序之间通讯服务,这种服务又称之为端到端。
  • 传输层与网络层不同,传输层只关心通讯的 起始端 和 目的端,并不在乎数据包的传输中转过程。
  • TCP :(transmission control Protocol 传输控制协议):提供面向连接的,一对一的可靠数据传输协议。
  • UDP :(user datagram Protocol 用户数据报协议):提供无连接的,不可靠的尽力的传输协议,但是效率更高
(4) 应用层
  • 负责处理应用程序的逻辑

HTTP/HTTPS
超文本传输协议,万维网数据通信的基础
http:明文发送, https加密传输

邮件协议
收: POP3(post office protocol)邮局协议第三个版本
从服务器接收右键,接收完后服务器就没有这个邮件了;

发: SMTP(简单邮件传输协议)

IMAP: 交互式邮件存储协议,与POP3类似的邮件访问标准协议之一。
收取邮件后,服务器上邮件依然存在,如果删除、标记服务器也会做相应操作。

FTP(FILE Transfer Protocol)
文件传输协议,是用于在网络上进行文件传输的一套标准协议,使用TCP传输

TFTP
简单文件传输协议,适用于在网络上进行文件传输的一套标准协议,使用UDP传输

DNS
Telnet/ssh :远程登录

1.2.4 网络封包与拆包


MTU :

  • Maximum Transmission Unit 最大传输单元
    • 物理接口(数据链路层)提供给上层(网络层(IP层))最大一次传输数据的大小。
    • 规定了数据链路层所能传送最大数据长度
    • 以太网为例,缺省MTU=1500字节,这是以太网接口对IP层的约束
    • 如果IP层<=1500字节需要发送,只需要一个IP包就可以
    • 如果IP层>1500字节需要发送,需要分片才能发送(分片:帧)

MSS:

  • Maximum Segment Size 最大报文长度
    • TCP提交给IP层最大分段大小,指TCP报文所允许传送数据部分最大长度。
    • 不包含TCP头,MSS式TCP来限制应用层最大发送字节数。
    • 如果MTU=1500,则MSS = 1500-20(IP header)-20(TCP header) =1460字节
    • 如果应用有2000字节要发,需要2 Segment
    • 第一个TCP Segment = 1460 第二个TCP Segment = 540

1.3 TCP和UDP协议的异同点(重点!!!)

  • 相同点: 都属于传输层协议
  • 不同点:
  1. TCP
1. 是提供面向连接的,可靠的稳定的数据传输协议。
2. 数据在传输过程中,无误,无丢失,无失序,无重复到达的通信。
	1.1 每一个数据包都会编上一个编号,该编号称之为序列号(seq),且每一个数据包都需要一个正确的应答包应答
	1.2 应答包:应答数据包,且通知对方下一次从哪个包开始发送(应答号:ack)。
3. 超时重传机制。
3. 传输效率低,耗费资源多。
4. 在数据链路层限制数据包大小(46~1500bytes),超出部分分帧发送。
5. 数据的收发是不同步的,会粘包(不存在数据边界)
	5.1 粘包:为了提高效率,将多个足够小,且发送间隔极短的数据包合成一个包发送,该现象称之为粘包现象,该算法称之为Nagle算法。

适用场景: 适用于对传输质量要求比较高,传输大量数据的通信,在需要可靠数据传输的场合,通常使用TCP协议。
例如: 网上购物付钱的时候,装备购买,账户密码登录的时候

  1. UDP
1.是提供无连接的,不可靠的尽力的数据传输协议。
2.数据在传输过程中有可能出现,错误,丢失,失序,重复到达的通信。
3. 传输效率高
4. 限制每次传输的大小(46~1500bytes),超出部分直接删除。
5. 数据收发是同步的,不存在粘包现象(存在数据边界)

适用场景: 适用于对传输质量要求比较低,传输小尺寸数据的通信,给出应答比较困难的网络中使用。
例如: 广播/组播 直播 语音视频电话,多人竞技类游戏。

1.4 IP地址

  • IP地址是因特网中主机的标识,每个数据包都必须携带目的IP地址和源IP地址,路由器依靠此信息为数据包选择路由。
  • IP地址是路由器下发的。(自动,手动)

1.4.1 IP地址的分类

1. IPv4:占4个字节,采用32bit的无符号整数来存储IP地址。[0, 2^32-1],给你个2^32= 42.9亿
	1.1 局域网:为了解决IP地址不够用的问题,让多台主机使用同一个广域网IP地址。
	1.2 广域网:与外界通信的网络环境。
	1.3 每一个IP地址都可以下发一个局域网。

2. IPv6:占16个字节,采用128bit的无符号整数来存储IP地址。[0, 2^128-1]2.1 容量足够多,能够给地球上的每一粒沙子都分配一个IP地址。
	2.2 IPv4往IPv6过渡的阶段还未完成。IPv4和IPv6尚不兼容。
桥接模式和net模式的区别?
桥接模式:windows和ubuntu是兄弟关系,连接同一个路由器
net模式:windows当做路由器,下发一个网络给ubuntu

1.4.2 IP地址划分

  • 由于IP地址基数比较大,所以为了提高寻径效率,则将IP地址划分成二级IP地址;

    • 二级IP地址 = 网络号 + 主机号
    • 网络号: 确定计算机从属的物理网络地址(确定是哪个村子的)
    • 主机号: 确定网络号后,用主机号标识该网络号中的所有主机。(确定是哪个村子后,在村子中找到设备的编号)

    注意:

    • ABC类为基本类,可以分配给主机使用,且只有ABC类可以分配给主机使用
    • D类:不表示网络,用于特殊用途:组播,多播组
    • E类:保留,或者实验室使用。

1.4.3 点分十进制

  • 使用点分十进制是为了方便记忆。
  • 将32位IP地址的二进制数,以8bit为一组,用十进制表示,利用点分割
IP地址范围网络号个数主机号个数
A类地址0.0.0.0~127.255.255.2552^7(网络号)2^24(主机号)大型网络
B类地址128.0.0.0~191.255.255.2552^142^16名地址网管中心
C类地址192.0.0.0~223.255.255.2552^212^8校园网或企业网、家庭网
D类地址224.0.0.0~239.255.255.255组播地址
E类地址240.0.0.0~255.255.255.255保留

在ABC类中的特殊IP地址:不能分配给主机使用。(掐头去尾)

  • 网络地址:代表该网络的。由有效网络号 + 全是0的主机号组成
    如:
    110.1.2.3 —> A类IP地址 —>网络号是前8bit —>110.0.0.0
    129.1.2.3 —> B类IP地址 —>网络号是前16bit —>129.1.0.0
    200.1.2.3 —> C类IP地址 —>网络号是前24bit —>200.1.2.0
  • 广播地址:向该IP地址发送,代表给当前网络下的所有主机发送数据。由有效网络号 + 全是1的主机号组成
    如:
    110.1.2.3 —> A类IP地址 —> 网络号是前8bit —> 110.255.255.255
    129.1.2.3 —> B类IP地址 —> 网络号是前16bit —> 129.1.255.255
    200.1.2.3 —> C类IP地址 —> 网络号是前24bit —> 200.1.2.255

1.4.4 子网掩码(重点!)

  • 二级IP地址划分后,主机的基数还是比较大,所以引入了另外一个概念:子网掩码。利用子网掩码可以将主机号进行再次划分:
    • IP = 网络号 + 子网号 + 主机号
    • 三级划分比较灵活,可以选择划分,也可以选择不划分,可以选择划分出2部分,4部分,8部分…2^n(n=0,1,2…)
(1) 子网掩码的概念
  • 子网掩码 :用于将一个大的IP网络中的主机号划分为若干小的子网络(常用)。
    1. 指明一个IP地址的哪些位表示的是主机所在的子网
    2. 指明哪些位表示的是主机的位掩码。
    3. 子网掩码不能单独使用,必须结合IP地址一起使用

将若干个小网络组合成一个大的局域网(称之为超网技术)。

  • 子网掩码的格式:
    1. 与IP地址一样长的32位无符号整数,是由一串连续的1,后面跟着一串连续的0组成。
    2. 默认子网掩码的格式:
      1的个数与IP地址中网络号的个数一致
      0的个数与IP地址中主机号的个数一致。
(2) 默认子网掩码
A类IP地址的默认子网掩码:11111111 00000000 00000000 00000000 ===> 255.0.0.0
B类IP地址的默认子网掩码:11111111 11111111 00000000 00000000 ===> 255.255.0.0
C类IP地址的默认子网掩码:11111111 11111111 11111111 00000000 ===> 255.255.255.0
子网掩码是对主机号做再次划分,D类E类没有主机号,所以没有子网掩码。

C类IP地址的默认子网掩码:11111111 11111111 11111111 00000000 ===> 255.255.255.0
                       11111111 11111111 11111111 10000000 ===> 255.255.255.128
                       11111111 11111111 11111111 11000000 ===> 255.255.255.192
                       11111111 11111111 11111111 11100000 ===> 255.255.255.224
                       
                       11111111 11111111 11111111 00000011 ===> 1不连续错误的!!!
(3) 格式用法:IP & 子网掩码=子网网段
(1) 1个子网网段
192.168.125.229 & 255.255.255.0
11000000 10101000 01111101 11100101 ===> 192.168.125.229
11111111 11111111 11111111 00000000 ===> 255.255.255.0
------------------------------------------------------------------------------
11000000 10101000 01111101 00000000 ===> 192.168.125.0  子网网段
即192.168.125.229属于192.168.125.0该子网网段。
在00000000-11111111该范围内的主机号,&255.255.255.0这个子网掩码,得到的结果均为192.168.125.0  子网网段。
即0~255这个范围内的主机号,均为192.168.125.0  子网网段。
所以没有划分出新的子网,所有主机号都在192.168.125.0  子网网段内。

该子网网段可以写作:192.168.125.0/24 (24代表该子网网段是通过有241的子网掩码得到)。
这个子网网段内的主机号是多少个 2^8= 256个。
(2) 2个子网网段
192.168.125.229 & 255.255.255.128
11000000 10101000 01111101 1 1100101 ===> 192.168.125.229
11111111 11111111 11111111 1 0000000 ===> 255.255.255.128
----------------------------------------------------
11000000 10101000 01111101 1 0000000 ===> 192.168.125.128  子网网段
范围:如下范围的主机号[128, 255]& 255.255.255.128得到的结果均为192.168.125.128/25  子网网段。
11000000 10101000 01111101 1 0000000 ===> 192.168.125.128
11000000 10101000 01111101 1 1111111 ===> 192.168.125.255

192.168.125.127 & 255.255.255.128
11000000 10101000 01111101 0 1111111 ===> 192.168.125.127
11111111 11111111 11111111 1 0000000 ===> 255.255.255.128
----------------------------------------------------
11000000 10101000 01111101 0 0000000 ===> 192.168.125.0  子网网段
范围:如下范围的主机号[0, 127]& 255.255.255.128得到的结果均为192.168.125.0/25  子网网段。
11000000 10101000 01111101 0 0000000 ===> 192.168.125.0
11000000 10101000 01111101 0 1111111 ===> 192.168.125.127

综上所述,
通过255.255.255.128可以将192.168.125.0该网络划分出2个子网
每个子网中有2^7个主机号。


特殊的IP地址:

  • 每个子网网段中,都有自己的子网网段地址。有效网络号+有效子网号+全是0的主机号 。 掐头
  • 每个子网网段中,都有自己的子网广播地址。 去尾
  • 总结:每个子网网段都需要掐头去尾

1.4.5 网关

  • 网关是一个网络通向其他网络的IP地址
  • 目前家用路由器一般使用192.168.1.1和192.168.0.1作为LAN接口的地址,这个两个也是最常用的网关地址。

1.4.6 域名系统

  • 由于使用IP地址来指定计算机不方便人们记忆,且输入时候容易出错,用字符标识网络种计算机名称方法。

  • 这种命名方法就像每个人的名字,这就是域名(Domian Name)

  • 域名服务器(Domain Name server): 用来处理IP地址和域名之间的转换。

  • 域名系统(Domain Name System,DNS): 域名翻译成IP地址的软件

  • 一个域名,可以绑定多个ip

域名结构

  • 例如域名 www.baidu 从右向左看
    cn为高级域名,也叫一级域名,它通常分配给主干节点,取值为国家名,cn代表中国
    com为网络名,属于二级域名,它通常表示组织或部门
    中国互联网二级域名共40个,edu表示教育部门,com表示商业部门,gov表示政府,军队mil等等
    baidu为机构名,在此为三级域名,表示百度
    www:万维网 world wide web,也叫环球信息网,是一种特殊的信息结构框架。

1.4.7 端口号

  • 为了区分一台主机收到的数据包交给哪个进程处理,使用端口号来区分。程序启动后将端口号和进程绑定在一起。
  • 网络里面的通讯是由 IP地址+端口号 来决定
  • 端口号存储在 2个字节 无符号整数中 (unsigned short int)。[1, 65535]
  • 常见的端口号:
1~1023  端口我们编程时候不要使用,是那些 系统/规定 应用程序占了
	TCP 21端口:FTP文件传输服务
	TCP 23端口:TELNET终端仿真服务
	TCP 25端口:SMTP简单邮件传输服务
	TCP 110端口:POP3邮局协议版本3
	TCP 80端口:HTTP超文本传输服务
	TCP 443端口:HTTPS加密超文本传输服务
	UDP 53端口:DNS域名解析服务
	UDP 69端口:TFTP文件传输服务
  • 可以使用的:1024~49151,就是我们平时编写服务器使用的端口号
  • 临时端口号:49152~65535,这部分是客户端运行时候动态选择的

TCP和UDP的端口号是相互独立的: 有时TCP和UDP用到了同一个端口,也是能用的

2. 跨主机传输

2.1 字节序(重点!)

2.1.1 字节序的概念

  1. 字节序是不同类型CPU主机,内存存储 多字节整数 序列的方式。
    1. char 字符串 float double均没有字节序的说法
    2. short int long long long有字节序的说法
  2. 小端字节序:低字节存储在低地址上,高字节存储在高地址上。
  3. 大端字节序:低字节存储在高地址上,高字节存储在低地址上。

首地址都是低地址,数据的读取都是从低地址往高地址读取,经过大小端转换后得出结果。

2.1.2 本地字节序与网络字节序

本地字节数:主机字节序(Host Byte Order) HBO
网络字节序(Network Byte Order) NBO,网络字节序规定使用大端字节序。
在跨主机传输过程中,需要使用统一的字节序,即网络字节序,避免兼容性问题。

2.1.3 字节序转换函数

2.1.3.1 htons htonl 主机字节序–>网络字节序

头文件:
       #include <arpa/inet.h>uint32_t htonl(uint32_t hostlong);
       uint16_t htons(uint16_t hostshort);
参数:
    指定要转换成网络字节序的整型:分别是32bit和16bit;
返回值:
    成功,返回转换后网络字节序的整型​

示例:

#include <stdio.h>
#include <arpa/inet.h>int main(int argc, const char *argv[])
{
    unsigned int a = 0x87654321;
    printf("%#x\n", a);             //0x87654321
    printf("%#x\n", htonl(a));      //0x21436587printf("%#x\n", htons(a));      //0x2143                 
    
    return 0;
}   

2.1.3.2 ntohs ntohl 网络字节序---->主机字节序

头文件:
       #include <arpa/inet.h>
原型:
       uint32_t ntohl(uint32_t netlong);
       uint16_t ntohs(uint16_t netshort);
参数:
    uint32_t hostlong:32位网络字节序整型;
    uint16_t hostshort:16位网络字节序整型;
​
返回值:
    成功,返回转换成主机字节序的整型;

2.1.4 结构体对齐

  • 编译器会对结构体进行对齐,加速CPU取值周期,由于数据对齐也是与操作系统相关,不同的主机如果使用不同的对齐方式,会导致数据无法解析。
  • 所以网络传输结构体的时候需要取消结构体对齐;

例如:

#include <stdio.h>#pragma pack(1)         //设置默认对齐系数 :()中的参数只能填2^n (n=0,1,2,3,4,5......)  typedef struct
{
    char a;     //1
    int b;      //4
    int d;      //4
}_A;#pragma pack()      //重置默认对其系数,重新置为8typedef struct
{
    char a;     //1
    int b;      //4
    int d;      //4
} __attribute__((packed))  B;       //取消结构体对齐
​
​
typedef struct
{   
    char a;     //1
                //3
    int b;      //4
    int d;      //4
}_C;int main(int argc, const char *argv[])
{   
    printf("%ld\n", sizeof(_A));    //9
    printf("%ld\n", sizeof(_B));    //9
    printf("%ld\n", sizeof(_C));    //12return 0;
}

2.1.5 类型长度

  • 因为涉及到跨平台,不同平台会有不同的字长
  • int long int不同操作系统这两个数据类型所占的字节数可能是不一样的
  • 解决方式:可以通过通用类型:uint8_t uint16_t uint32_t
#include <stdint.h>typedef struct
{
    uint8_t a;      //1
    uint32_t b;      //4
    uint16_t d;      //2
}_A;

2.2 IP转换

  • 由于IP地址本质上是一个4个字节的无符号整数,所以在跨主机传输中也有字节序的概念。
  • 所以需要将IP地址转换成网络字节序。
  • “192.168.8.189” ---->本机字节序的整型 0xC0A808BD---->网络字节序0xBD08A8C0
  • “192.168.31.42”----> 0xC0A81F2A ---->0x2A1FA8C0

2.2.1 点分十进制—>网络字节序

2.2.1.1 inet_aton

  • 只能转换IPv4
头文件:
       #include <sys/socket.h>
       #include <netinet/in.h>
       #include <arpa/inet.h>
原型:
       int inet_aton(const char *cp, struct in_addr *inp);
参数:
    char *cp:源IP地址的点分十进制字符串,例如 “192.168.1.10;
    struct in_addr *inp:存储转换成网络字节序的IP;
           typedef uint32_t in_addr_t;
           struct in_addr {
               in_addr_t s_addr;
           };
返回值:
    成功,返回非0;
    失败,返回0;

例子:

 #define IP  "192.168.1.10"      //0xC0A8010A
 int main(int argc, const char *argv[])
 {
     struct in_addr inp;
 
     if(inet_aton(IP, &inp) == 0)
     {
         printf("转换失败\n");
         return -1;
     }
 
     printf("%#X\n", inp.s_addr);    //0X0A01A8C0
                                                           
     return 0;
 }                                                          

2.2.1.2 inet_pton

  • 既可以转IPv4也能处理IPv6
头文件:
       #include <arpa/inet.h>
原型:
       int inet_pton(int af, const char *src, void *dst);
参数:
    int af:协议族
            AF_INET         IPV4
            AF_INET6        IPV6
     char *src:指定要转换成网络字节序的点分十进制字符串;
     void* dst
           typedef uint32_t in_addr_t;
           struct in_addr {
               in_addr_t s_addr;
           };
​
            af == AF_INETa;
            struct in6_addr
            {
            }
返回值:
    成功,返回1;
    失败,返回0或者-1,更新errno;

例子:

#define IP "192.168.1.3" //0xC0A80103 --> 0x301A8C0 struct in_addr inp;
inet_pton(AF_INET, IP, &inp);
printf("%#X\n", inp.s_addr);        //0x301A8C0 

2.2.1.3 inet_addr

  • 最常用

  • 只能转换IPv4

    头文件:
    	#include <sys/socket.h>
    	#include <netinet/in.h>
    	#include <arpa/inet.h>
    原型:
    	uint32_t inet_addr(const char *cp);
    参数:
    	char *cp:源IP地址的点分十进制字符串,例如 “192.168.1.10;
    返回值:
    	成功,返回转换后的网络字节序IP地址;
    	typedef uint32_t in_addr_t;
    	​
    	失败,返回INADDR_NONE (usually -1);
    

例子:

printf("%#X\n", inet_addr(IP));

2.2.2 网络字节序—>点分十进制

2.2.2.1 inet_ntoa 常用

  • 只能转换IPv4;
头文件:
       #include <sys/socket.h>
       #include <netinet/in.h>
       #include <arpa/inet.h>
原型:
       char *inet_ntoa(struct in_addr in);
参数:
    struct in_addr in:指定要转换成点分十进制字符串的IP地址;
           typedef uint32_t in_addr_t;
           struct in_addr {
               in_addr_t s_addr;
           };
返回值:
    成功,返回点分十进制字符串的首地址;
printf("%s\n", inet_ntoa(inp));

2.2.2.2 inet_ntop

头文件:
       #include <arpa/inet.h>
原型:
       const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
参数:
    int af:协议族
            AF_INET         IPV4
            AF_INET6        IPV6
    void* src:存储要转换成点分十进制字符串的IP首地址;
           typedef uint32_t in_addr_t;
           struct in_addr {
               in_addr_t s_addr;
           };
​
            af == AF_INETa;
            struct in6_addr
            {
            }
    char *dst:存储转换后的结果,点分十进制的首地址;
    socklen_t size:缓冲区大小,其实就是指定多大的空间用于转换IP;
返回值:
    成功,返回字符串的首地址,就是dst;
    失败,返回NULL,更新errno;    

例子:

char ip[20];
if(inet_ntop(AF_INET, &inp, ip, sizeof(ip)) == NULL)
{
	perror("ient_ntop");
	return -1;                                            
}
printf("%s\n", ip);

本文标签: 网络编程 嵌入式 基础 计划