0%

做 iOS 开发的都知道,打包必需准备好 证书配置文件;没有这两个,将无法打包给别人测试或者上传 App Store

那什么是证书?什么是配置文件呢?要了解这两个东西,先来了解一下其原理。

签名

我们知道,数据在传输过程中,安全性很重要;接收方怎么判断接收到的数据是 完整的 并且是 合法的 呢?

  1. 完整性:是指数据自发送方发出后,在到达接收方的过程当中未发生任何改动、丢失。
  2. 合法性:是指 接收方 接收到的数据是来自可信赖的 发送方

MD5消息摘要算法

MD5 消息摘要算法(MD5 Message-Digest Algorithm):是一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。

MD5 摘要

完整性

发送方通过 MD5 算法 对数据生成 摘要(Digest),然后把数据和摘要一起传输;接收方在接收到数据之后,通过同样的 MD5 算法对数据部分生成摘要,再通过对比接收的摘要是否一致来判断数据是否完整。
数据完整性

阅读全文 »

按键标识

按键 Mac OS 释义 类似 Windows 释义
Command win
Control Control
Option alt
Shift Shift

快捷键

Command 部分

快捷键组合 作用
Command + N 新建文件
Command + Option + N 新建工程目录(Finder 中不存在)
Command + Shift + N 新建工程
Command + O 打开文件
Command + W 关闭 Xcode
Command + B 编译
Command + R 运行
Command + . 停止
Command + K 清空控制台打印信息
Command + Shift + K 清除工程
Command + 1 工程导航器
Command + 2 符号导航器
Command + 3 搜索导航器
Command + 4 问题导航器
Command + 5 测试导航器
Command + 6 调试导航器
Command + 7 断点导航器
Command + 8 报告导航器
Command + 0 显示/隐藏导航器面板
Command + Option + Enter 打开双视图
Command + Enter 关闭双视图
Command + Option + 0 显示/隐藏使用工具面板
Command + Shift + Y 显示/隐藏调试面板
Command + F 当前类搜索
Command + G 一搜索处
Command + Shift G 一搜索处
Coomand + Shift + F 全局搜索
Command + L 跳转到指定行
Command + Shift + 0 快速打开 Apple 文档
Command + Shift + O 快速查找类并打开
Command + Shift + J 快速定位当前类在项目文件中的位置
Command + Control + ↑/↓ 类文件 .h.m 之间切换
Command + Control + ← 按照浏览文件的顺序 后退
Command + Control + → 按照浏览文件的顺序 前进
Command + Option + ← 收起 方法体
Command + Option + → 展开 方法体
Command + Shift + ← 选中光标往 所有代码
Command + Shift + → 选中光标往 所有代码
Command + / 注释代码
Command + \ 设置断点
Command + Z 撤销
Command + Shift + Z 反撤销
Command +[ 选中的代码向 位移
Command +] 选中的代码向 位移
Command + Option + [ 选中的代码向 位移
Command + Option + ] 选中的代码向 位移

Control 部分

快捷键组合 作用
Control + 6 当前类 方法/变量查找
Control + F 光标向 移一个字符
Control + B 光标向 移一个字符
Control + P 光标向 移一行
Control + N 光标向 移一行
Control + A 光标移到 行首
Control + E 光标移到 行尾
Control + T 调换光标两边的字符
Control + D 删除光标 右侧 字符
Control + K 删除本行 剩余 的字符
Control + I 格式化代码
阅读全文 »

Little endianBig endian 是 CPU 存放数据的两种不同方式。

对于整型、长整型等数据类型:

  1. Big endian :认为第一个字节是最高位字节(按照从低地址到高地址的顺序存放数据的高位字节到低位字节);
  2. Little endian :认为第一个字节是最低位字节(按照从低地址到高地址的顺序存放数据的低位字节到高位字节)。

例如,假设从内存地址0x0000 开始有以下数据:0x12, 0x34, 0xab, 0xcd

Endian 0x0000 0x0001 0x0002 0x0003
big-endian 0x12 0x34 0xab 0xcd
little-endian 0xcd 0xab 0x34 0x12

问题:如何判断系统中的 CPU 是 Little endian 还是 Big endian 模式?(假设机器为:32 位

解答:将一个字节的数据和一个整型数据存放于同样的内存始地址,通过读取整型数据,分析数据在整型数据的高位还是低位来判断 CPU 是 Little endian 还是 Big endian 模式。

  1. 例码1:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    typedef enum __endianType {
    Endian_little,
    Endian_big,
    }EndianType;

    EndianType CheckEndian1()
    {
    typedef unsigned char BYTE;

    unsigned int num, *p_num;
    p_num = #
    num = 0; // 设置 num 占用的所有字节内容都为:0x00
    *(BYTE *)p_num = 0xff; // 通过指针类型强制转换并对整型数据《首字节》赋值,判断该赋值赋给了高位还是低位

    if(0xff == num)
    {
    return Endian_little;
    }
    else // 0xff000000 == num
    {
    return Endian_big;
    }
    }
  2. 例码2:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    typedef enum __endianType {
    Endian_little,
    Endian_big,
    }EndianType;

    EndianType CheckEndian2()
    {
    union {
    unsigned int a;
    char c;
    }endianUnion;

    endianUnion.a = 1;

    if (1 == endianUnion.c)
    {
    return Endian_little;
    }
    else
    {
    return Endian_big;
    }
    }
  3. 例码3:(Linux 内核的实现方式)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    typedef enum __endianType {
    Endian_little,
    Endian_big,
    }EndianType;

    EndianType CheckEndian3()
    {
    union {
    char c[4];
    unsigned int num;
    } endianUnion = {'l', '?', '?', 'b'};

    if ('l' == (char)endianUnion.num) // 取首字节判断
    {
    return Endian_little;
    }
    else // 'b' == (char)endianUnion.num
    {
    return Endian_big;
    }
    }
阅读全文 »

回顾

上一例子已经了解了 TCP 客户端与服务端的保活技术:心跳机制

现在通过模拟客户端请求服务端对远端用户的一些操作进行实战演练(远程唤醒用户实战列子。)。

本例子由客户端给服务器发送相关请求数据包,基本流程思路:

  1. 设计相关的通信协议(数据结构);
  2. 服务端根据客户端的不同请求命令,执行响应的操作予以回复客户端。

例子

相关通信协议

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/** 命令类型 枚举 */
typedef enum __cmdType {
Cmd_reqStatus = 0x01, // 请求用户状态
Cmd_respStatus = 0x02, // 回复用户状态
Cmd_reqWakeUp = 0x03, // 请求唤醒用户
Cmd_respWakeUp = 0x04, // 回复唤醒用户
Cmd_reqSuspend = 0x05, // 请求挂起用户
Cmd_respSuspend = 0x06, // 回复挂起用户
}CmdType;


/** 用户状态 枚举 */
typedef enum __userStatus {
Status_unknow = 0, // 未知状态
Status_online = 1, // 在线状态
Status_waking = 2, // 正在唤醒
Status_suspending = 3, // 正在挂起
Status_suspended = 4, // 挂起状态
Status_offline = 5, // 离线状态
}UserStatus;


/** 消息类型 枚举 */
typedef enum __msgType {
Msg_heart = 0, // 心跳包
Msg_other = 1, // 其他数据
}MsgType;


/** 消息头 结构体 */
typedef struct __msgHead {
MsgType msgType; // 消息类型
unsigned int msgLen; // 消息长度
char data[0]; // 消息实体
}MsgHead;


/** 请求消息体 结构体 */
typedef struct __msgReq {
unsigned int magic; // 魔术符
unsigned int cmd; // 命令类型
unsigned char userId[0]; // 用户id号
}MsgReq;


/** 响应消息体 结构体 */
typedef struct __msgResp {
unsigned int magic; // 魔术符
unsigned int cmd; // 命令类型
unsigned int status; // 用户状态
unsigned char userId[0]; // 用户id号
}MsgResp;

Server

server.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#ifndef TCPServer_hpp
#define TCPServer_hpp

#include <iostream> // cout
#include <sys/socket.h> // socket
#include <netinet/in.h> // sockaddr_in
#include <arpa/inet.h> // inet_addr
#include <unistd.h> // close
#include <map> // map


#define BUFF_SIZE 4096 // 缓存大小
#define HB_INTERVAL 3 // 心跳时间间隔(单位:秒)
#define CHECK_HB_COUNT 5 // 无法检测到心跳最大次数


/** 返回值 枚举 */
typedef enum __retValue {
Ret_error = -2, // 出错
Ret_failed = -1, // 失败
Ret_success = 0, // 成功
}RetValue;


void* CheckHeartBeat(void* arg); // 心跳检测


class TCPServer
{
private:
struct sockaddr_in serverAddr; // 服务端地址
socklen_t serAddrLen; // 地址长度
int serverSockfd; // 服务端 socket
struct timeval timeout; // 超时时间
int maxFd; // 最大 sockfd
fd_set masterSet; // 所有 sockfd 集合,包括服务端 sockfd 和所有已连接 sockfd
fd_set workingSet; // 工作集合
std::map<int, std::pair<std::string, int>> sockfdMap; // 记录连接的客户端 : <sockfd, <ip, checkCount>>

/**
接受客户端连接

@return 参见‘RetValue’
*/
RetValue AcceptConn();

/**
接收客户端消息

@return 参见‘RetValue’
*/
RetValue RecvMsg();

/**
格式化发送数据

@param buf 数据缓冲区
@param bufLen 缓冲区长度
@param cmd 命令类型
@param status 用户状态
@param userId 用户 ID
@return > 0:格式化成功(需要发送数据大小);否则,失败
*/
int RespDataFormat(char *buf, unsigned int bufLen, unsigned int cmd, unsigned int status, const char userId[]);

/**
解析接收的数据

@param buf 数据缓冲区
@param msgLen 消息长度
@param cmd 命令类型
@param userId 用户 ID
@return 解析是否成功;0:成功,否则失败
*/
int ReqDataParse(char *buf, unsigned int msgLen, unsigned int *cmd, char *userId);

/**
心跳检测

@param arg 线程参数(TCPServer实例指针)
*/
friend void* CheckHeartBeat(void* arg);

public:
TCPServer(std::string ipStr, unsigned int port);
~TCPServer();

/**
绑定 服务端 地址

@return 参见‘RetValue’
*/
RetValue BindAddr();

/**
监听端口连接请求

@param queueNum 最大等待处理连接队列数
@return 参见‘RetValue’
*/
RetValue Listen(unsigned int queueNum);

/**
运行服务端

@return 参见‘RetValue’
*/
RetValue Run();


};

#endif /* TCPServer_hpp */
阅读全文 »

回顾

上一例子已经了解了 TCP 客户端与服务端相互通信;但是在通信过程中,怎么知道对方已经掉线了呢?这就需要心跳机制

心跳,就是每每隔一定时间间隔,给对方发送个消息,让对方知道自己还活着,以确保连接的有效性。心跳的发送方可以是服务端,也可以是客户端;不过比较起来,前者开销就比较大。

本例子由客户端给服务器发送心跳包,基本流程思路:

  1. 如果服务端接收到的是心跳包,将该客户端对应的心跳检查计数器 count 清零;
  2. 在心跳检查线程中,每隔一定时间(假定:10秒)遍历所有已连接的客户端的心跳检查计数器 count
    • count 小于 一定的检查次数(假定:6次),将 count 计数器加 1;
    • count 大于等于设定的检查次数(假定:6次),说明已经(超过 1分钟 )未收到该用户心跳包,则判定该用户已经掉线;
  3. 客户端则建立心跳发送线程,定时(假定:10秒)给服务器发送心跳包。

相关函数

fd_set

struct fd_set 可以理解为一个集合,这个集合中存放的是**文件描述符(filedescriptor)**,即文件句柄。Unix下任何设备、管道、FIFO等都是文件形式,所以 socket 就是一个文件,socket句柄就是一个文件描述符。fd_set 相关操作如下:

  1. FD_ZERO:清空集合。
  2. FD_SET:将一个给定的文件描述符加入集合之中。
  3. FD_CLR:将一个给定的文件描述符从集合中删除。
  4. FD_ISSET:检查集合中指定的文件描述符是否可以读写。

timeval

用来代表时间值,有两个成员。

阅读全文 »

回顾

上一例子已经了解了与socket相关几个基本函数,知道了 TCP 连接通信的基本流程:

TCP连接通信流程

上一个例子中仅仅是客户端与服务的连接后通信一条消息,这是最简单的 TCP 例子;现在则进一步引入Pthread,为客户端单独创建一个接收信息和发送信息的线程,使其可以随时的跟服务端通信。而为服务端单独创建一个与客户单进行通信的线程,负责接收客户的消息的接收以及响应(这里直接回复客户端发来的消息)。

pthread

POSIX线程(POSIX threads),简称 pthreads,是线程的POSIX标准。该标准定义了创建和操纵线程的一整套API。在类Unix操作系统(Unix、Linux、Mac OS X等)中,都使用 pthreads 作为操作系统的线程。

在多线程程序中经常用到的两个函数:pthread_create()pthread_join()

pthread_create

  1. 头文件:#include<pthread.h>

  2. 功能:创建线程,在线程成功创建以后,就开始运行相关的线程函数。

  3. 原型:

    1
    int pthread_create(pthread_t *tidp, const pthread_attr_t *attr, (void*)(*start_rtn)(void*), void *arg);
  4. 参数:

    • tidp:指向线程 ID 的指针。
    • restrict_attr:用于指定各种不同的线程属性。
    • start_rtn:线程运行函数的起始地址。
    • arg:运行函数的参数。如果需要向start_rtn函数传递的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为 arg 的参数传入。
  5. 返回值:

    • 成功:返回 0。
    • 失败:返回出错编号。
  6. 注意:因为pthread并非Linux系统的默认库,而是 POSIX 线程库。在Linux中将其作为一个库来使用,因此加上 -lpthread(或 -pthread)以显式链接该库。函数在执行错误时的错误信息将作为返回值返回,**并不修改系统全局变量 errno**,所以无法使用perror()打印错误信息。

pthread_join

阅读全文 »

选项 可能存在于多层协议中,它们总会出现在最上面的 socket 层;当操作 socket 选项时,选项位于的层和选项的名称必须给出。

选项相关函数

setsockopt

  1. 头文件: #include<sys/socket.h>

  2. 功能: 设置与 socket 关联的选项。

  3. 原型:

    1
    int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);
  4. 参数:

    • sock: 将要被设置选项的 socket

      • level: 选项所在的协议层。

        含义
        SOL_SOCKET 通用 socket 选项
        IPPROTO_IP IP 选项
        IPPROTO_TCP TCP 选项
      • optname: 需要设置的选项名。

      • optval: 指向包含新选项值的缓冲(根据选项名称的数据类型进行转换)。

      • optlen: 选项值的最大长度

  5. 返回值:

    • 0: 成功。

      • -1: 失败,错误原因可以通过 error 获得

        含义
        EBADF sock 不是有效的文件描述符
        EFAULT optval 指向的内存并非有效的进程空间
        EINVAL optlen 无效
        ENOPROTOOPT 指定的协议层不能识别选项
        ENOTSOCK sock 描述的不是 socket

getsockopt

  1. 头文件: #include<sys/socket.h>

  2. 功能: 获取与 socket 关联的选项。

  3. 原型:

    1
    int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);
  4. 参数:

    • sock: 将要被获取选项的 socket

    • level: 选项所在的协议层。

      含义
      SOL_SOCKET 通用 socket 选项
      IPPROTO_IP IP 选项
      IPPROTO_TCP TCP 选项
    • optname: 需要获取的选项名。

    • optval: 指向返回选项值的缓冲(根据选项名称的数据类型进行转换)。

    • optlen: 选项值的实际长度。

  5. 返回值:

    • 0: 成功。

    • -1: 失败,错误原因可以通过 error 获得

      含义
      EBADF sock 不是有效的文件描述符
      EFAULT optval 指向的内存并非有效的进程空间
      ENOPROTOOPT 指定的协议层不能识别选项
      ENOTSOCK sock 描述的不是 socket

选项

协议层 选项名 说明 数据类型
SOL_SOCKET SO_BROADCAST 允许发送广播数据 int
SO_DEBUG 允许调试 int
SO_DONTROUTE 不查找路由 int
SO_ERROR 获得套接字错误 int
SO_KEEPALIVE 保持连接 int
SO_LINGER 延迟关闭连接 struct linger
SO_OOBINLINE 带外数据放入正常数据流 int
SO_RCVBUF 接收缓冲区大小 int
SO_SNDBUF 发送缓冲区大小 int
SO_RCVLOWAT 接收缓冲区下限 int
SO_SNDLOWAT 发送缓冲区下限 int
SO_RCVTIMEO 接收超时 struct timeval
SO_SNDTIMEO 发送超时 struct timeval
SO_REUSERADDR 允许重用本地地址和端口 int
SO_TYPE 获得套接字类型 int
SO_BSDCOMPAT 与BSD系统兼容  int
IPPROTO_IP IP_HDRINCL 在数据包中包含IP首部 int
IP_OPTINOS IP首部选项 int
IP_TOS 服务类型 int
IP_TTL 生存时间 int
IPPRO_TCP TCP_MAXSEG TCP最大数据段的大小 int
TCP_NODELAY 不使用Nagle算法 int
阅读全文 »

在网络编程中,socket 是核心内容,如果无法理解 socket 到底是什么,那么在做网络编程开发时,将会困难无比。在开始一个最简单的 TCP 例子之前,最好先了解一下什么是 socket,以及常用的与 socket 编程相关的函数。

什么是 socket?

socket是什么?在维基是这样说的:在计算机科学中,网络套接字(英语:Network socket),又译网络套接字、网络接口、网络插槽,是电脑网络中进程间数据流的端点。

在 Unix 中,一切都是文件,socket 也不例外,也是一个特殊的 “文件描述符”;所以对 socket 的也有类似文件的操作,如:readwriteclose 等。

socket 相关函数

socket

  1. 头文件:#include<sys/socket.h>

  2. 功能:建立一个协议族为 domain、协议类型为 type、协议编号为 protocolsocket 文件描述符。(当创建成功后,socket 在名称空间(网络地址族)中存在,但没有任何地址给它赋值。)在服务器端,socket()返回的套接字用于监听 (listen) 和接受 (accept) 客户端的连接请求,这个套接字不能用于与客户端之间发送和接收数据;在客户端则是用于与服务端之间发送和接收数据。

  3. 原型:

    1
    int socket(int domain, int type, int protocol);
  4. 参数:

    • domain:用于设置网络通信的域,该函数根据这个参数选择通信协议的族。

      名称 含义
      PF_UNIXPF_LOCAL 本地通信
      AF_INETPF_INET IPv4 Internet 协议
      PF_INET6 IPv6 Internet 协议
      PF_IPX IPX-Novell 协议
      PF_NETLINK 内核用户界面设备
      PF_X25 ITU-T X25 / ISO-8208 协议
      PF_AX25 Amateur radio AX.25
      PF_ATMPVC 原始 ATM PVC 访问
      PF_APPLETALK Appletalk
      PF_PACKET 底层包访问
    • type:用于设置套接字通信的类型。

      名称 含义
      SOCK_STREAM TCP 连接,提供序列化的、可靠的、双向连接的字节流。
      SOCK_DGRAM 支持 UDP 连接(无连接状态的消息)。
      SOCK_SEQPACKET 序列化包,提供一个序列化的、可靠的、双向的基本连接的数据传输通道,数据长度定常。每次调用读系统数据需要将全部数据读出。
      SOCK_RAW RAW 类型,提供原始网络协议访问。
      SOCK_RDM 提供可靠的数据报文,不过可能数据会有乱序。
      SOCK_PACKET 这是一个专用类型,不能在通用程序中使用。
    • protocol:用于制定某个协议的特定类型,即 type 类型中的某个类型。(通常某协议中只有一种特定类型,这样 protocol 参数仅能设置为 0;但是有些协议有多种特定的类型,就需要设置这个参数来选择特定的类型。)

      • SOCK_STREAM 类型的套接字表示一个双向的字节流,与管道类似。流式的套接字在进行数据收发之前必须已经连接,连接使用 connect() 函数进行。一旦连接,可以使用 read() 或者 write() 函数进行数据的传输。流式通信方式保证数据不会丢失或者重复接收;当数据在一段时间内仍然没有接受完毕,可以将这个连接人为关闭。
      • SOCK_DGRAMSOCK_RAW 这个两种类型的套接字可以使用函数 sendto() 来发送数据到指定的 IP 地址;使用 recvfrom() 函数接收指定 IP 地址的数据。
      • SOCK_PACKET是一种专用的数据包,它直接从设备驱动接受数据。
  5. 返回值:

    • > 0:创建成功,返回一个标识这个 socket 的文件描述符。

    • -1: 创建失败;错误原因可以通过error获得。

      含义
      EACCES 没有权限建立制定的 domain 的 type 的 socket
      EAFNOSUPPORT 不支持所给的地址类型
      EINVAL 不支持此协议或者协议不可用
      EMFILE 进程文件表溢出
      ENFILE 已经达到系统允许打开的文件数量,打开文件过多
      ENOBUFS/ENOMEM 内存不足
      EPROTONOSUPPORT 制定的协议 type 在 domain 中不存在

bind(服务端)

  1. 头文件:#include<sys/socket.h>

  2. 功能:把用 addr 指定的地址赋值给用文件描述符代表的 sockfd;addrlen 指定了以 addr 所指向的地址结构体的字节长度。(该操作常称为“给socket命名”。)

  3. 原型:

    1
    int bind(int sockfd, const struct sockaddr *addr, socklen_t *addrlen);
  4. 参数:

    • sockfd:需要绑定地址的 socket。
    • addr:需要连接的地址;一般设置时使用 struct sockaddr_in,之后在使用到的函数参数中强制转换为 struct sockaddr *
    • addrlen:地址参数长度。
  5. 返回值:

    • 0:成功。

    • -1:出错,错误原因可以通过 error 获得。

      含义
      EACCESS 地址空间受保护,用户不具有超级用户的权限。
      EADDRINUSE 给定的地址正被使用。

listen(服务端)

阅读全文 »

地址转换函数

在 socket 编程中,对于地址转换函数,BSD包含 inet_addr(), inet_aton()inet_ntoa() 三个函数用于二进制地址格式与点分十进制之间的相互转换,但是仅仅适用于 IPv4;inet_ntop()inet_pton() 具有相似的功能,并且同时支持 IPv4 和 IPv6;字母p代表presentation,字母n代表numeric。

inet_addr

  1. 头文件:#include <arpa/inet.h>

  2. 功能:该函数用于将 点分十进制 IP 地址转换成 网络字节序 IP 地址。

  3. 原型:

    1
    in_addr_t inet_addr(const char *cp);
  4. 返回值:如果正确执行,将返回一个无符号长整数型数;如果传入的字符串不是一个合法的IP地址,将返回 INADDR_NONE

inet_aton

  1. 头文件:#include <arpa/inet.h>

  2. 功能:该函数用于将 点分十进制 IP 地址转换成 网络字节序 IP 地址。

  3. 原型:

    1
    int inet_aton(const char *string, struct in_addr *addr);
  4. 返回值:如果正确执行,函数的返回值非零,如果输入地址不正确则会返回零。

inet_ntoa

  1. 头文件:#include <arpa/inet.h>

  2. 功能:该函数用于 网络字节序 IP 转化 点分十进制 IP 地址。

  3. 原型:

    1
    char *inet_ntoa (struct in_addr);
  4. 返回值:如果正确执行,将返回一个字符指针;否则,返回 NULL

inet_pton

  1. 头文件:#include <arpa/inet.h>

  2. 功能:该函数用于将 点分十进制 IP 地址转换成 网络字节序 IP 地址。

  3. 原型:

    1
    int inet_pton(int domain, const char *restrict str, void *restrict addr);
  4. 返回值:如果正确执行,返回1;如果参数格式无效,返回0;如果出错,返回-1。

阅读全文 »

dup、dup2 函数

dupdup2 都是用来复制一个文件的描述符;常用来重定向进程的 stdinstdoutstderr

头文件

1
#include <unistd.h>

函数原型

1
2
int dup(int oldfd);
int dup2(int oldfd, int targetfd);

返回值

1
返回一个新的描述符,这个新的描述符是传给它的描述符的拷贝。

功能

  1. 都是用来复制一个文件的描述符。
  2. dup2 函数跟 dup 函数相似,但 dup2 函数允许调用者规定一个有效描述符和目标描述符的id 。dup2` 函数成功返回时,目标描述符(dup2函数的第二个参数)将变成源描述符(dup2函数的
    第一个参数)的复制品。换句话说,两个文件描述符现在都指向同一个文件,并且是函数第一
    个参数指向的文件。
阅读全文 »