Linux网络编程

========================== 基础知识 =============

授课过程中名词的规范:
计算机处理的数据: 数据包
物理网卡处理的数据: 数据帧

IP地址:网间通信协议地址,用来在网络通信中唯一标识一台主机。
IP地址目前有两类, IPv4、IPv6,目前主流是IPv4,未来的趋势是IPv6。
IPV4地址是32bit的整数,IPv6地址是128bit的整数。

IP地址的表示:
二进制整数: 11000000 10101000 00000001 00000001
点分十进制: 192.168.1.1
十六进制: 0xc0a80101

IP地址 = 网络地址 + 子网地址 + 主机地址。
主机地址全0标识该网段,主机地址全1是该网段的广播地址,因此都不可以标识主机。
只有相同网络地址的主机才能直接通信。

IPv4地址的分类:
A类:32bit中以0开头的地址。1字节网络地址 + 3字节主机地址。用来管理超大规模的网络,通常是国家级的通信主干网。
0.0.0.0 ~ 127.255.255.255
10网段是私有IP,用作搭建大型局域网。
127网段是保留地址,用作本地环回。

B类:32bit中以10开头的地址。2字节网络地址 + 2字节主机地址。用来管理大规模的网络。
128.0.0.0 ~ 191.255.255.255
172.16.xx.xx - 172.31.xx.xx私有地址

C类:32bit中以110开头的地址。3字节网络地址 + 1字节主机地址。用来管理小型的网络。
192.0.0.0 ~ 223.255.255.255
192.168.xx.xx是C类的私有地址。

D类:32bit中以1110开头的地址。组播地址,不用来标识主机,也不划分网段。
224.0.0.0 ~ 239.255.255.255
E类:32bit中以11110开头的地址。	用作实验、测试等,不用做标识主机。
240.0.0.0 ~ 247.255.255.255

子网掩码:
用来在ABC类网段基础下划分子网,子网掩码和IP地址“位与”后得到网络段号,即“子网掩码 & IP地址 = 网络地址”。
例如:
11000000 10101000 00000001 00001010 192.168.1.10 IP地址
11111111 11111111 11111111 00000000 255.255.255.0 子网掩码
11000000 10101000 00000001 00000000 192.168.1.0 网络段

划分子网分类管理,可减少网关的负载并预防广播风暴。
广播风暴:网络中大量主机发送广播数据包并要求应答时,数据总量将会是主机数量N的平方级,引发网络瘫痪。

网关/路由器
工作在L3,网络层,解析IP, 负责管理该网段内的所有主机,面向主机跨越不同网段,是组成整个因特网的骨干。

交换机
工作在L2, 数据链路层,负责根据MAC面向网卡转发数据帧。

DNS: 域名解析系统,负责将域名解析成对应的IP地址。
域名: 一个字符串,用来描述一台主机,通常用在浏览器中访问目标服务器。
例如:
192.168.1.1 点分十进制表示的IP地址,网络通信使用,不方便记忆
www.baidu.com 域名,一组有特征的字符串,用户使用,方便人记忆。
8.8.8.8 谷歌提供的全球免费DNS服务器地址

调制解调器/“猫”:
ADSL线路的模拟信号到本地局域网数字信号的转换,根据数据发送的双向特性,具有调制和解调功能。

OSI的7层模型,一个理想的网络通信模型,每层分别负责不同的协议。
应用层
表示层
会话层
传输层
网络层
数据链路层
物理层

TCP/IP模型, 一个现有的工业标准,计算机世界的通用语。
应用层
传输层
网络层
物理层

套接字的类型:
流式套接字(TCP)
用户数据报套接字(UDP)
原始套接字

TCP: 可靠的、面向连接的、双工的、基于字节流的通信方式,不限制数据的长度。
UDP: 不可靠的、无连接的、双工的、基于用户数据报的通信方式,有固定的最大长度限制。

UDP包大小不能超过65535字节(因为UDP包头中用2字节表示包大小),但是实际能传输的最大包是65535-20-8(IP包头和UDP包头分别占用20和8字节)
TCP没有大小限制。
IP包头中也用2字节表示IP包大小,因此IP包大小也不能超过65535,IP层会使用分片机制拆分过大的TCP数据包。
数据链路层的ETHER帧默认大小不能超过1500字节,因此网卡发送数据前也会拆包并在接收时重组。

大小端:
X86 小端字节序
Arm 大小
PPC 大端

TCP粘包问题:TCP协议层为了节省开销会将多个小数据的包合并成一个大包一起发送出去,因此会发生数据粘连。
解决方案:
1.使用setsockopt()函数设定TCP层的属性禁止发送方粘包(man 7 tcp),但是不能解决接收方的粘包。
2.在每次发送后延时十几ms, 但是将导致发送效率低下。
3.发送方和接收方规定每次按照定长收发数据,但是当数据长度浮动范围较大时会浪费资源(为了对齐不得不发送无用的脏数据)。
4.将数据封装,定长包头+变长数据,每次接收先接定长的包头,根据包头中记录的数据长度再接收定长的数据。(此法从效率和占用资源上都达到均衡)。

主机字节序:
大端字节序
小端字节序

网络字节序:大端字节序

========================== 基本接口 =============

通用结构体:
struct sockaddr {
  		sa_family_t sa_family;	/* unsigned short , 指定了通信协议家族 */
char sa_data[14];
};
IPV4网络通信地址结构体:
struct sockaddr_in {
pa_family_t sin_family;
port_t sin_port;
struct in_addr {
unsigned int s_addr;
}sin_addr;
};
UNIX本地通信地址结构体:
struct sockaddr_un {
sa_family_t sun_family;
char sun_path[108];
};
函数名:int socket (int domain, int type, int protocl)
功能: 打开一个套接字,并返回一个相关的文件描述符。
返回值:成功, 一个新的文件描述符; 失败, -1;
参数表:
int domain, 通信域:
AF_INET | AF_INET6 | AF_UNIX | AF_PACKET
int type, 套接字类型:
SOCK_STREAM 流式套接字
SOCK_DGRAM 数据报套接字
SOCK_RAW 原始套接字
int protocl, 协议(在原始套接字中根据需要选择使用, 流式或数据报套接字中为 0.
函数名: int bind(int sockfd, const struct sockaddr * addr, socklen_t addrlen);
功能: 为一个打开的套接字,绑定一个地址(IP+PORT)。
返回值: 成功, 0; 失败, -1;
参数表:
int sockfd, 通过socket打开并返回的文件描述符。
const struct sockaddr * addr, 通用结构体地址,具体根据通信域选择相关的地址格式。
socklen_t addrlen, 实际地址结构体的大小。
函数名: int sendto(int sockfd, void *buff, size_t size, int flag, const struct sockaddr *addr, socklen_t addrlen);
功能: 向一个指定的目标主机发送数据包。
返回值: 成功, 实际发送的字节数; 失败, -1;
参数表:
int sockfd, 通过socket打开并返回的文件描述符。
void *bufff, 即将发送的数据。
size_t size, 数据大小。
int flag, 发送标志位(阻塞、非阻塞等, 如果无特殊要求则设置为0)。
const struct sockaddr * addr, 目标主机的地址结构体(IP+PORT)。
socklen_t addrlen, 目标主机地址结构体大小。
函数名: int recvfrom(int sockfd, void *buff, size_t size, int flag, struct sockaddr *addr, socklen_t *addrlen);
功能: 接受一个数据包,并带回数据包的来源地址。
返回值: 成功, 实际接收的字节数; 失败, -1; 对方关闭, 0;
参数表:
int sockfd, 通过socket打开并返回的文件描述符。
void *bufff, 接受数据的缓冲区。
size_t size, 缓冲区大小。
int flag, 接收标志位(阻塞、非阻塞等, 如果无特殊要求则设置为0)。
struct sockaddr * addr, 用来保存数据源主机的地址的结构体(IP+PORT)。
socklen_t *addrlen, 期望接收的数据源主机的地址结构体大小(在使用前由用户自己初始化);一旦该函数调用结束,该变量会被修改为实际大小。
函数名: int listen(int sockfd, int backlog);
功能: 将一个经过bind的套接字置为被动状态,以便将来使用accept接受新的请求。
返回值:成功, 0; 失败, -1;
参数表:
int sockfd, 通过socket创建,并通过bind后的套接字描述符。
int backlog, 握手请求队列的最大值。
函数名: int accept(int sockfd, struct sockaddr * addr, socklen_t addrlen);
功能: 接受一个握手请求,并返回一个新的文件描述符。
返回值: 成功, 新的文件描述符(用来收发数据的通道); 失败, -1;
参数表:
int sockfd, 经过socket创建,bind后并且listen后的文件描述符。
struct sockaddr *addr, 用来带回握手请求方的地址结构体。
socklen_t addrlen, 期望接收的对方的地址大小,该值会被修改为实际大小,调用者需提前初始化。
函数名: int select(int nfds, fd_set *rdfds, fd_set *wrfds, fd_set *exceptfds, struct timeval * timval);
功能: 在多路IO复用模型中,负责检测多个文件描述符资源。但没有资源可操作时,进程阻塞; 有资源操作时返回可操作的资源个数。
返回值: 成功, 资源个数; 失败, -1; 超时, 0;
参数表:
int nfds, 检测的最大描述符值+1.
fd_set *rdfds, 希望监测的读资源描述符集合。
fd_set *wrfds, 希望监测的写资源描述符集合。
fd_set *wrfds, 希望监测的其他资源描述符集合。
ftruct timeval *timval, 超时监测,设定秒+微秒。
select相关函数:
FD_SET(int fd, fd_set * fds): 将描述加入集合中。
FD_CLR(int fd, fd_set *fds): 将指定描述从集合中移除。
FD_ZERO(fd_set *fds):	 清空一个描述符集合。
FD_ISSET(Iint fd, fd_set *fds): 测试一个描述符是否在集合中(测试该描述符资源是否可操作);
其他函数接口:
int send(int sockfd, const void *buff, size_t size, int flag);
int recv(int sockfd, void *buff, size_t size, int flag);
getpeername(int connfd, struct sockaddr *addr, socklen_t *addrlen);
getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
setsockopt(int level, int optname, const void *optval, socklen_t optlen);
short htons(short );
int htonl(int);
short ntohs(short);
int ntohl(int);

--------------- 编程模型 ------------------
UDP编程接口:
客户端:
socket(): 打开一个套接字并返回文件描述符。
htons(): 将2字节的本机字节序转换成网络字节序。
inet_addr(): 将点分十进制的IP地址转换成二进制的IP地址,并且按照网络字节序存放。
sendto(): 向目标主机发送一个数据包。
recvfrom();
close();
服务器端:
socket();
bind(): 向内核注册一个本地IP和端口号,一旦有客户端向该IP和端口发送数据包,内核会通知本进程。
recvfrom();
sendto();
close();
TCP编程接口:
客户端:
socket();
connect();
send()/write();
recv()/read();
close();
服务器端:
socket();
bind();
listen();

accept();
recv()/read();
send()/write();
close();

======================== 服务器模型 =============

循环服务器:
单任务完成服务众多客户端的请求,待服务的客户端需排队等待服务。
优点: 简单、轻量、易于实现。
缺点: 服务效率不高,无法同时服务多个请求。一旦有客户端恶意占用服务时间,会导致排队的客户端无法接受服务。

基于UDP的echo服务器。

并发服务器:
多任务完成服务每个客户端的请求,每个客户端不需要排队等待,可以立即进行服务。
优点: 服务效率高,客户端无需等待。
缺点: 复杂、较多地占用了系统的资源,一旦客户端过多会严重浪费系统资源。

IO多路复用服务器:
单任务服务多个客户端,但是由于使用了IO多路复用模型,让一个进程可以同时监测多路IO通道,因此每个任务无需等待。
优点: 轻量、服务效率高。
缺点: 实现复杂、服务数量受限于每个任务能够打开的最大IO通道数。并且由于确认IO通道采用轮询方式,一旦客户端过多效率会降低。

IO模型:
阻塞IO:
当进程没有IO资源时,进程将进入睡眠状态直到有资源可读。
因此当单个进程通过阻塞IO操作多路IO时,要求多路IO严格同步,否则将导致服务效率极低。
节省系统资源,服务效率低, 要求IO通道间同步。

非阻塞IO(轮询):
即使进程没有IO资源也不阻塞,仅仅造成IO函数出错返回。
当单个进程通过非阻塞IO操作多路IO时,不需要IO通道间同步,但是需要轮询。
需要轮询, 严重消耗系统资源, 服务效率高, 不要求IO通道间同步。

IO多路复用:
单个进程同时监测多路IO, 没有任何IO资源时进程阻塞睡眠,有任何IO资源可用时进程唤醒。
服务效率高,节省系统资源。但是因为需要轮询(在select返回后),当监测的IO通过过多时,效率有所损失。

异步IO:
进程不等待IO资源不轮询,一旦有IO资源,系统主动通知进程去访问。
需要底层驱动支持。
信号驱动IO
异步通知

==================== 广播 ======================

广播是一对多通信。
主机地址全1是该网段的广播地址。
广播只能发向同一个网段,并且该网段内的所有主机都可以接收。
由于广播是一对多通信,因此不能使用面向链接的流式套接字,只能使用无连接的数据报套接字。

发送方将数据发向广播地址;
接收方绑定广播地址;

================ 组播 ==========================

组播(多播)是一种向特定群组发送广播的方式。

D类IP地址是组播地址,组播地址用来描述一个组播组,不用来了标识任何主机。
保留组播地址: 224
公有组播地址: 225 ~ 238
私有组播地址: 239

发送方把数据发向组播地址。
接收方要提前加入组播组内, 接收方要绑定组播地址。

================ 超时监测 ======================

  1. select
  2. alarm
  3. setsockopt

================== 安全策略 =====================

arp攻击
dos攻击
sql注入
死亡之ping

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值