Linux网络编程
day1:
1 网络基础
1.1 网络体系结构
网络设备=网络终端设备+网络中继(传输)设备
网络体系结构:网络的分层模型和每层所使用的协议的集合
有两种:OSI 7层 应用层 表示层 会话层 传输层 网络层 数据链路层 物理层
TCP/IP 4层 应用层 传输层 网络层 物理层–》在使用
1.2 IP地址–》网络地址
定义:在网络中唯一标识一台主机符号就是IP地址(唯一标识一台主机的符号是MAC地址)
ipv4维护IP地址
4:1 IP协议的版本号是V4
2 IPV4协议维护的IP地址宽度是4byte=32bit
ipv4协议提供了2^32个IP地址,将这些地址分成了5类:
A 1.0.0.1~126.255.255.254
B 127.0.0.1~191.255.255.254
C 192.0.0.1~223.255.255.254 -->用户IP地址 24网络号+8主机号
D 224.0.0.1~239.255.255.254–》组播地址
E 240.0.0.1~255.255.255.254–>保留地址
unsigned int addr=inet_addr(“127.0.0.1”);
1.3 网络协议
定义:在网络通信中对某种通信规则的约定
分类:1 网络通用协议(TCP/IP协议族)
2 行业内部专有协议
3 自定义协议
1.4 端口号
作用:用作标识一个应用进程
是一个unsigned int 的整数,表示范围1-65535
1-1023已被著名的协议或程序占用,用户可用:1024~65535
1.5 字节序
主机字节序:是不同的CPU主机存贮多字节整数的方式,有大端主机字节序,有小端主机字节序
大端主机字节序:将数据的高字节存放在内存的低地址上
小端主机字节序:将数据的高字节存放在内存的高地址上
注意:由于网络通信中两台主机的字节序有可能不同,会造成发送的数据和接收的数据反序,所以在传送网络数据前要做字节适配处理,将多字节整数从主机字节序转换成网络字节序
网络字节序:是大端字节序,用于兼容通信双方的字节序
htonl:将4字节的数据的主机字节序转换成网络字节序
htons:将2字节的数据的主机字节序转换成网络字节序
2 基于TCP协议网络客户端&服务端模型
服务端:socket–>bind–>listen–>accept–>IO函数(read/write recv/send)
客户端:socket–>connect–>IO函数
struct sockaddr linux系统头文件中
struct sockaddr--->16byte
{
__SOCKADDR_COMMON (sa_); 2byte
char sa_data[14]; 14byte
};
#define __SOCKADDR_COMMON(sa_) \
sa_family_t sa_family;
struct sockaddr_in-->16byte
{
__SOCKADDR_COMMON (sin_); 2byte
in_port_t sin_port; 2byte
struct in_addr sin_addr; 4byte
unsigned char sin_zero[sizeof (struct sockaddr) -
__SOCKADDR_COMMON_SIZE -
sizeof (in_port_t) -
sizeof (struct in_addr)]; 8byte
};
int socket(int domain, int type, int protocol);
作用:创建一个用于通信的网络套接字
参数1:协议域 AF_INET(ipv4协议)
参数2:套接字类型 SOCK_STREAM
参数3:需要的其他协议 0--》自动匹配其他必要协议
返回值:失败 -1
成功 标识socket通道的文件描述符 >3
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
作用:给socket通道绑定网络接收终端
参数1:文件描述符 socket的返回值
参数2:表示本机地址信息的结构体指针
参数3:地址结构体的长度
返回值:0 成功 -1 失败
int listen(int sockfd, int backlog);
作用:监听客户端的连接请求
参数1:文件描述符 socket的返回值
参数2:服务端一次最大监听的客户端个数
返回值:0 成功 -1 失败
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
作用:接收客户端的连接请求
参数1:文件描述符 socket的返回值
参数2:地址信息结构,用来存放接收到的客户端的地址信息
参数3:存放第二个参数大小的变量的地址
返回值:成功 返回新的文件描述符--》标识一个新的socket通道--》用于收发数据,失败 -1
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
作用:接收socket通道中的数据
参数1:新的文件描述符 是accept的返回值
参数2:本地接收buf
参数3:期望接收的字节数
参数4:是否阻塞的接收的标志 0表示阻塞接收
返回值:>0 成功接收到的子节数
-1 失败
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
作用:往socket通道中发送数据
参数1:新的文件描述符 是accept的返回值
参数2:本地发送buf
参数3:期望发送的字节数
参数4:是否阻塞的发送的标志 0表示阻塞发送
返回值:成功 返回发送的字节数
失败 -1
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
作用:连接服务端
参数1:文件描述符 socket的返回值
参数2:目标服务器的主机地址信息结构
参数3:第二个参数的长度
返回值:0 成功 -1 失败
day2:
1 基于udp协议的网络客户端和服务端模型
服务端:socket-->bind-->IO函数(sendto/recvfrom)
客户端:socket-->IO函数(sendto/recvfrom)
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
参数1:文件描述符
参数2:接收buf
参数3:期望接收的字节数
参数4:阻塞或非阻塞标志 0--》阻塞
参数5:用来保存对方地址信息
参数6:参数5的长度的地址
返回值:成功 期望接收到的字节数 失败 -1
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
参数1:文件描述符
参数2:发送buf
参数3:期望发送的字节数
参数4:阻塞或非阻塞标志 0--》阻塞
参数5:用来存放对方地址信息
参数6:参数5的长度
返回值:成功 期望发送的字节数 失败 -1
总结:TCP协议的通信模型&UDP协议的通信模型
TCP是一个可靠的,全双工的,有序的,面向链接的字节流通信的协议。
为什么可靠:
1.丢失的数据包重发 (能保证拿到数据)
2.错误的数据包重发 (保证能拿到正确的数据)
3.数据的有序到达(因为对每个数据包进行了编号)(拆包,编号)
4.有较为健全的校验机制(为了保证数据的正确性)
5.支持面向连接(保证通信线路的畅通)-->三次握手
6.有信道拥堵控制(通过一种对于信道拥堵解决的方案,来提高转发效率)
产生的原因,是中继设备中(接收的速度 >> 发送的速度)
为什么有序(有序列号):
1.保证数据都能传输给对端,不至于当传输的数据 > 信道带宽
,导致数据丢弃。
2.通过序号,在对端主机上可以拼接成原本的数据包
3.保证数据传输的可靠性
如何面向链接:
三次握手和四次挥手
UDP:
UDP(The User Datagram Protocol):无连接的数据报协议,别名"不可靠的协议"
<1>使用校验和来实现错误侦测
<2>UDP常用于媒体流的传输(音频、视频、等),在这种情况下,实时性比
可靠性更重要
<3>UDP也常用于简单的查询/回应程序,例如DNS查找,在这种情况下,
建立可靠传输的资源消耗太大
<4>UDP是一种实时传输协议(Real-time Transport Protocol),这种协议
通常用来传输实时数据例如:音视频流
不可靠的原因:
1.非面向连接(不关心接收端是否在线)–》没有三次握手
2.丢包不重发
3.错误的包不重发
4.没有信道拥堵控制
5.有一个最大传输长度限制
6.没有严格的校验机制
问题:使用UDP通信模型,如何保证发送数据相对可靠性?可以采用重传机制
如何抉择使用TCP还是UDP
1.可靠性
2.实时性
可靠性 > 实时性: TCP
可靠性 < 实时性: UDP
tcp/udp是传输层的两个协议,他们的区别是:
tcp:是面向连接的可靠的传输协议
udp:是面向无连接的不可靠的传输协议
常见套接字类型:
流式套接字(SOCK_STREAM)
提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复的发送且按发送顺序接收。内设置流量控制,避免数据流淹没慢的接收方。数据被看作是字节流,无长度限制。
数据报套接字(SOCK_DGRAM)
提供无连接服务。数据包以独立数据包的形式被发送,不提供无差错保证,数据可能丢失或重复,顺序发送,可能乱序接收。
原始套接字(SOCK_RAW)–ping.c可以对较低层次协议如IP、ICMP直接访问
2 IO模型
linux 系统提供了4种IO模型:
2.1阻塞IO
若要读的数据没有准备好,或要写入的目标没有空间,将会发生读写阻塞
阻塞函数:优点:一直等待结果,直到等到结果
缺点:如果等待的接收数据的通道坏掉或文件损坏,那么当前进程会一直被挂起
2.2非阻塞IO
若要读的数据没有准备好,IO函数返回一个约定的错误值,不阻塞当前进程,可以通过循环去多次尝试读取数据。
非阻塞函数:优点:没有读到数据不阻塞当前进程,而是直接返回,带回一个错误值
2缺点:多次调用系统调用函数会有极大的系统资源开销。
2.3IO多路复用
思想:分三步
1 构建一个文件描述符集合表,表的大小是1024bit位,每一个bit表示一个文件描述符所对应的IO通道上是否有数据发生(或者IO通道是否活跃?)?如果有数据发生,该bit位为1,其他bit位被置位0。
2 使用select函数监控制定范围的文件描述符所对应的IO通道是否有数据发生,如果有数据发生,该函数返回通道的个数,并且将文件描述符集合表的相应bit置位1,同时将其他bit置位0,如果没有数据发生,那么select将阻塞当前进程。
3 对文件描述符集合表中的置位结果做出相应的判断,使用FD_ISSET判断该文件描述符在描述符集合表中是否为1,如果为1,响应这路IO数据,否则不处理。
分析:1 文件描述符集合表–》文件描述符对应的IO通道是否有数据发生
fd_set stFdr;1024bit
2 select 监控 置位–》stFdr
3 对stFdr中的置位情况做判断 0–>fgets 3–》accept 4–>recv/send
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
作用:监控文件描述符对应的IO通道是否有数据发生
参数1:要监控的文件描述符的最大个数
参数2:读文件描述符集合表
参数3:写文件描述符集合表
参数4:异常文件描述符集合表
参数5:超时时间 ,若为NULL,表示将select变成阻塞函数
返回值:成功 有数据发生的通道的个数
失败 -1