这里写目录标题
网络基础概念
网络协议初识
OSI七层模型:
物理层,数据链路层,网络层,传输层,会话层,表示层,应用层
TCP/IP五层模型
- 应用层:负责应用程序之间的数据传输,程序员就是工作在这一层面
典型的协议:HTTP协议,FTP协议,DNS协议,SMTP协议 - 传输层:负责端与端之间的数据传输
典型的协议:TCP协议,UDP协议 - 网络层:负责路由选择和地址管理
典型的协议:IP协议,ICMP协议,典型的设备:路由器 - 数据链路层:负责相邻设备之间的数据帧传输的
典型的协议:以太网 典型的设备:交换机 - 物理层:负责光电信号传输
典型的协议:以太网协议 典型的设备:集线器
IP地址和端口
IP地址(ipv4):
作用:在网络当中唯一标识一台主机
本质:unit32_t值,无符号4个字节,最大范围是42亿多
采用点分十进制,每个字节最大能够表示的数字为255
ip地址分为源ip地址和目的ip地址
网络通信中,每一条数据都是需要具备5条信息
5元组=源IP地址+源端口+目的ip地址+目的端口+protocol
ipv6:
1.ipv4和ipv6指的是不同版本的ip协议
2.ipv6并不向下兼容ipv4,原因就是两者的ip协议的报头格式都是不一样
3.ipv6是16字节的整数,2^128
port:
- 1.端口是在一台主机当中标识一个进程
- 2.本质:unit16_t端口的范围为0~ 2^16(0~ 65535)其中0~1023是知名端口,mysql是3306端口,oracle是1521端口
- 3.网络当中的程序,通信的时候,都是需要使用端口进行通信的
- 4.IP地址 + 端口号能够标识网络上的某一台主机的某一个进程;
- 5.一个端口号只能被一个进程占用.
TCP和UDP
TCP:传输层协议
- 面向连接:tcp的网络通信双方在发送数据之气需要先建立连接,才可以发送数据
- 可靠传输:保证TCP数据包可靠的到达对端
- 面向字节流:对于TCP数据可以随意的存取
UDP:传输层协议
- 无连接:UDP通信的双方在发送数据之前不需要建立连接,只需要知道对方的ip和port就可以直接发送
- 不可靠:如果UDP数据在网络当中传输的时候,丢失掉了,则不会保证udp数据一定到达对端了
- 面向数据报:UDP在发送数据的时候,是整条发送整条接收的
网络字节序
字节序:CPU对内存当中的数据进行存取的顺序
大端字节序:低地址存高位
小端字节序:低地址存高位
0x01020304 当中,01为高地址位,04为低地址位
x86_64架构的机器都是小端字节序
网络字节序:大端字节序
小端机器和大端机器进行通信的时候,如果不转换字节序,则会造成小端机器很小的数字,经过网络传输,被大端机器读成很大的数字
主机字节序:代表的是当前机器的字节序
字节序的转换:
大端字节序转换成网络字节序----》网络字节序就是大端字节序
- unit32_t htonl(unit32_t hostlog):将32位的主机字节序转换成网络字节序,即小端字节序转换成大端字节序
- unit32_t ntohl(unit32_t netlog):将32位的网络字节序转换成主机字节序
- unit16_t htons(unit16_t hostshort):将16位的主机字节序转换成网络字节序
- unit16_t ntohs(unit16_t netshort):将16位的网络字节序转换成主机字节序
h表示host,n表示network,l表示32位长整数,s表示16位短整数。
socket编程接口
创建套接字(TCP/UDP,客户端+服务器)
int socket(int domain,int type,int protocol)
- domain:地址域,设置网络层使用什么协议
网络层:ipv4–》AF_INET
ipv6—>AF_INET6 - type:套接字类型
传输层:tcp/udp
流式套接字:默认协议是tcp,不支持udp–》SOCK_STREAM
数据报套接字:默认协议是udp,不支持tcp—》SOCK_DGRAM - protocol:指定套接字使用的协议
0:采用套接字默认的类型
IPPROTO_TCP—>6
IPPROTO_UDP—>17 - 返回值:返回套接字的操作句柄,其实就是一个文件描述符,我们称之为套接字描述符
绑定地址信息(TCP/UDP,服务器)
int bind(int sockfd,const sockaddr*addr,socklen_t addrlen)
sock:套接字操作句柄
addr:地址信息 ip+port
struct sockaddr
{
sa_family_t sa_family; //填充地址域,告诉bind函数,网络层使用什么协议
char sa_data[14]; //填充地址信息,IP+PORT
}
struct sockaddr_in
{
__SOCKADDR_COMMON (sin_);//2个字节的地址域信息 AF_INET
in_port_t sin_port; /*typedef uint16_t in_port_t; *///两个字节的无符号整数
struct in_addr sin_addr; /* Internet address. */四个字节的无符号整数
/* Pad to size of `struct sockaddr'. */
unsigned char sin_zero[sizeof (struct sockaddr) -
__SOCKADDR_COMMON_SIZE -
sizeof (in_port_t) -
sizeof (struct in_addr)];
};
typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr;
};
- IPv4和IPv6的地址格式定义在 /usr/include/netinet/in.h中,IPv4地址用sockaddr_in结构体表示,包括16位地址类型, 16位端口号和32位IP地址.
- IPv4、IPv6地址类型分别定义为常数AF_INET、AF_INET6. 这样,只要取得某种sockaddr结构体的首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容.
- socket API可以都用struct sockaddr *类型表示, 在使用的时候需要强制转化成sockaddr_in; 这样的好处是程序的通用性, 可以接收IPv4, IPv6, 以及UNIX Domain Socket各种类型的sockaddr结构体指针做为参数;
bind接口在设计的时候为了通用各种协议,定义了一个结构体struct sockaddr;而在进行具体协议地址信息绑定的时候,填充不同的结构体,之后将结构体的对象的地址,强转传参给bind函数
socklen:地址信息的长度,防止有的协议地址信息长度大于16个字节,所以传递地址信息长度,告诉bind函数,应该如何去解析地址信息
发送数据
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
- sockfd:套接字描述符
- buf:待发送的数据
- len:发送数据的长度
- flags:0表示阻塞
- dest_addr:目标主机地址信息
- addrlen:地址信息长度
1.UDP也是有发送缓冲区的,只不过UDP的特点是整条发送,所以在发送的缓冲区当中加上UDP的协议报头之后就直接提交给网络层
2.阻塞发送的含义:当发送缓冲区当中有数据的时候,再次调用sendto接口,会阻塞等待,直到上一条数据发送完毕,sendto才会将数据写到发送缓冲区当中
接收数据
size_t recvfrom(int sockfd,void* buf,size_t len,int flags,struct sockaddr* src_addr,socklen_t* addrlen);
- sockfd:套接字描述符
- buf:从接收缓冲区当中拿到数据放到哪一个buffer当中
- len:buffer的最大长度,意味着最大可以接收多少数据,预留’\0’的位置
- flags:0:阻塞
- src_addr:源主机的地址信息(标识这条数据从哪一个主机上面的哪一个进程来)
- addrlen:地址信息长度,同时是一个输入输出型参数
关闭套接字
close(int sockfd)