在TCP/IP协议族中,有很多种协议。TCP/IP协议群中的核心协议被设计运行在网络层和传输层,它们为网络中的各主机提供通信服务,也为模型的最高层–应用层中的协议提供服务。其中的TCP和UDP协议就是应用在传输层的协议。
1. IP地址的作用
IP地址用来标识网络中的一台主机。
本篇文章主要讨论基于IPV4协议的网络通信。
2. IP地址的格式转换
IP地址有两种格式:十进制点分形式和32为二进制形式。前者=是大众所熟悉的形式,后者是网络传输中IP地址的存储方式。
十进制点分形式 “192.168.1.1”
32位二进制形式 10111110 10101000 00000001 00000001
IPv4地址转换函数: inet_aton(); inet_addr(); inet_ntoa();
#include
#include
#include
char *inet_ntoa(struct in_addr address);//返回点分十进制形式
in_addr_t inet_addr(const char *cp);//返回二进制地址形式
参数:
cp 点分十进制IP地址字符串
返回值:
成功返回 转换后的二进制地址形式
h: 主机host
to: 转换
s: short类型
l: long类型
n: network网络
#include
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
参数:
hostshort 主机字节序的 16bit数据
hostlong 主机字节序的 32bit数据
netshort 网络字节序的 16bit数据
netlong 网络字节序的 32bit数据
返回值:
成功返回 转换后的字节序值,失败返回 -1;
/* 通常地址结构 */
struct sockaddr {
unsigned short sa_family; //地址族 AF_XXX
char sa_data[14]; //14字节的协议地址
}
/* Internet协议地址结构 */
struct sockaddr_in
{
short int sin_family; //地址族 2bytes
unsigned short int sin_port; //端口号 2bytes
struct in_addr sin_addr; //IPv4地址 4bytes
unsigned char sin_zero[8]; //填充0 以保持与struct sockaddr同样大小 8bytes
}
/* IPv4地址结构 */
struct in_addr {
u_int32_t s_addr; /* 按网络字节次序(大端序)的地址 */
};
TCP,传输控制协议,是一种面向连接的传输层协议,向应用层提供可靠的面向连接的数据流传输服务。它能提供高可靠性通信(数据无误、数据无丢失、数据无失序、数据无重复到达)。
创建套接字:
#include /* See NOTES */
#include
int socket(int domain, int type, int protocol);
参数:
domain:选择协议族
AF_UNIX UNIX域协议:本地通信
AF_LOCAL 同AF_UNIX
AF_INET IPv4协议
AF_INET6 IPv6协议
AF_ROUTE 路由套接字
AF_KEY 密钥管理协议,密钥套接字
type:选择套接字类型
SOCK_STREAM 流式套接字
SOCK_DGRAM 数据包datagram套接字
SOCK_RAW 原始套接字
protocol:
0 (原始套接字除外)
返回值:
成功返回 套接字描述符,失败返回 -1;
绑定套接字:
/* bind 函数原型 */
#include
#include
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
参数:
sockfd 套接字描述符
my_addr 绑定客户端地址:不同协议族结构体定义不同,传参时需要强转为通用结构体
addrlen 客户端地址信息长度
返回值:
成功返回 0,失败返回 -1;
监听:
#include
int listen(int sockfd, int backlog);
参数:
sockfd: 套接字描述符
backlog:能够同时监听的客户端个数(不是同时能连接的个数)
返回值:
成功返回 0,错误返回 -1;
接收客户端连接请求:
#include
#include
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数:
sockfd socket返回的监听套接字描述符
addr 用于保存客户端地址信息,若不需要填NULL
addrlen 客户端地址信息长度,若不需要填NULL
返回值:
错误返回 -1,正确返回 用于通信的套接字;
客户端向服务器请求连接:
#include /* See NOTES */
#include
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
参数:
sockfd 套接字描述符
addr 服务器端地址
addrlen 地址长度
返回值:
成功返回 0,失败返回 -1;
发送数据:
#include
#include
int send(int sockfd, const void *msg, size_t len, int flags);
参数:
sockfd 套接字描述符
msg 发送缓冲区的地址
len 发送数据的长度
flags 一般为 0
返回值:
成功返回 实际发送的字节数,失败返回 -1;
接收数据:
#include
#include
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
参数:
sockfd 套接字描述符
buf 存放接收数据的缓冲区
len 接收数据的长度
flags 一般为0
返回值:
成功返回 实际收到的字节数,失败返回 -1;
UDP,用户数据报协议,是一种面向无连接的不可靠传输层协议。具有资源消耗小,处理速度快的特点。
由于UDP通信之前不需要先建立一个连接,因此UDP应用要比TCP应用更加简单,高效,也能更好的解决实时性问题。
UDP服务器流程:
- socket();
- bind();
- recvfrom(); / sendto();
- close();
UDP客户端流程
- socket();
- recvfrom(); / sendto();
- close();
一些函数同上,介绍两个一般用于UDP接收发送的函数,也可用于TCP。
接收数据:
#include
#include
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
参数:
sockfd socket函数的返回值,套接字描述符
buf 接收数据的缓冲区地址
len 接收数据的大小
flags 一般为 0
src_addr 发送端的结构体的地址
addrlen 发送端的结构体长度的地址
返回值:
成功返回接收的字节数,失败返回 -1
发送数据:
#include
#include
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
参数:
sockfd socket函数的返回值,套接字描述符
buf 发送数据的缓冲区
len 发送数据的大小
flags 一般为 0
dest_addr 接收端的结构体的地址
addrlen 接收端的结构体长度的地址
返回值:
成功返回发送的字节数,失败返回 -1