linux网络设备和一些知识点总结

FTP客户端和服务器之间的沟通需要四步:
1.启动FTP
2.建立控制连接(根据客户给出的服务器IP地址向提供FTP服务的21号端口主动建立连接请求,控制连接在用户
退出之前一直存在)
3.建立数据连接和进行文件传输(客户端会生成一个临时TCP端口号和IP地址,使用服务器上的20端口向客户端
主动建立请求,客户端接收并三次握手后就建立了另一条TCP连接--数据连接,客户端将文件写入传输进程网
络流中然后服务器端将传输来的文件在服务器端的文件系统中进行存储)
4.关闭FTP
主动模式情况下FTP端口固定在20而被动模式的服务器数据端口则在1025~65535之间的随机数。

socket在传输过程中不同时间的包有可能会合并,socket会在每个包后面自动补全n个0x0 byte来分割包。
TCP保证了包发送的顺序是不会变的,因此这个是解决分包黏包问题的关键。
服务器端开发的常见问题:队列缓存,防止客户端连接短时间暴涨,请求频率过重,连接时间记录,发送信息
长度记录(避免内存爆满宕机)
服务器端环境其实是很糟糕的,在处理业务逻辑中的任何时候都可能会因为连接中断而断开。
服务器接收到的客户端请求可以是任意字符串,因此必须对各种可能的输入都进行判断。

TCP粘包:由于Nagle算法用于自动连接小缓存器消息的算法来提高效率,解决方法:设置固定的结构体,设置TCP_NODELAY,设置固定长度的TCP包。

libpcap由两部分组成:网络分接口(Network Tap)和数据过滤器(Packet Filter),从网卡的链路层数据包进行过滤,把匹配成功的消息传至内核缓冲区再传递给消息缓冲区。
常用函数:
1.设备名指针:pcap_lookupdev()函数用于查找网络设备,返回可被pcap_open_live()函数调用的网络设备名指针。
2.设备描述字:pcap_open_live()函数用于打开网络设备,并返回用于捕获网络数据包的捕获描述字。对于此网络设备的操作都要基于此网络设备描述字。
3.设备网络号和掩码:pcap_lookupnet()函数用来获得指定网络设备的网络号和掩码。
4.pcap_compile()函数用于将用户制定的过滤策略编译到过滤程序中。
5.pcap_setfilter()函数用于设置过滤器。
6.pcap_loop()函数、pcap_dispatch()函数用于捕获数据包,捕获后还可以进行处理。pcap_next()和pcap_next_ex()两个函数也可用于用来捕获数据包。
7.pcap_dump_open()函数用于保存捕获数据包的文件,用于写入。pcap_open_offline()打开以前打开以前保存捕获数据包的文件,用于读取。
8.pcap_close()函数用于关闭网络设备,释放资源等。
mmap技术建立核心态内存和用户态内存的映射,将系统分配给网卡设备文件的核心态内存映射到一块用户态内
存,这样应用程序可以通过调用系统函数recvfrom()函数从网卡直接拷贝到用户态内存中,减少一次数据拷贝
可以提高捕获效率。


libpcap可以自定义数据包发送,流量采集与统计,数据包捕获,规则过滤。

通过真值树解析布尔表达式:生成真值表,根据真值表生成真值树,真值树是一个二叉树,如果能同时按层深度索引真值树能走到叶子节点说明本次表达式为true。GCC语法树,预先将所有的可能值都求一遍再缓存起来。

编译原理:语言和文法、词法分析、语法分析、语法制导翻译、中间代码生成、存储管理、代码优化和目标代码生成。
编译程序锁使用的中间代码(IR)有多种形式,常见的有逆波兰、三元式、四元式和树形表示。四元式常称为三地址代码。

setsockopt():由于TCP中很多函数是阻塞的,1.超时机制:也就是需要setsockopt来设置超时时间。2.多路复用机制:select()

ioctl()中主要问题在于理解cmd命令码是怎么在用户程序里生成并在驱动程序里解析的。主要工作量在于switch{case}结构进行相应的操作。驱动程序中最难的是对中断的理解。ioctl还能进行的工作有锁上它的门,弹出它的介质,报告错误信息,改变波特率,或者自我销毁。

IOCP与epoll之间的比较:IOCP中封装了I/O功能而epoll只会返回当前是否可读可写,与I/O功能分离,提供了更高的灵活性。具有一样的底层机制:协议栈的状态检查不需要用户去查询而是由作业系统来通知。如果当前IO通道传输过于缓慢我们可以将这个IO通道分离出来交由阻塞模型去进行处理,而让epoll处理快速通道,然而IOCP不具有这种控制能力。一个客户端一个线程的代价:维护线程消耗堆栈内存,创建销毁线程代价过大,线程之间的上下文切换代价太大。因此我们做了一次将网络连接和I/O工作线程分离为两部分,仅依靠I/O进行通讯。同步模式:一线程一客户端,早晚因为开销太大而出事。异步模式:以轮询方式检查各个连接是否收到数据。而现多使用IOCP方式,首先是根据CPU数量来建立线程池,利用网卡的DMA等特性将网络数据写入内存,再动态调用线程来处理数据

ioctl()也就是处理字符设备驱动的函数,有很多宏。
设备驱动与底层硬件直接打交道,按照硬件设备的具体工作方式读写设备寄存器,完成设备的轮询、中断处理、DMA通信,进行物理内存向虚拟内存的映射,最终使得通信设备能够收发数据,使显示设备显示文字和画面,使存储设备能够记录文件和数据。因此设备驱动是硬件和应用软件之间的纽带。
无操作系统的典型架构:while(1){if(serialInt==1){ProcessSerialInt();serialInt=0;}
if(keyInt==1){ProcessKeyInt();keyInt=0;}
status=CheckXXX();switch(status){}
}
没有操作系统的话无法处理多个并发的任务,通过给设备驱动制造麻烦来达到给上层应用提供便利的目的。操作系统给我们提供内存管理机制,设备驱动需要按照独立于设备的接口而设计,这样可以使用统一的接口来访问各种设备。应用程序通过read()、write()等函数就可以访问各种字符设备和块设备。

设备分为:字符设备(触摸屏、鼠标、磁带驱动器)、块设备(磁盘、软驱,经过系统的快速缓冲)、网络设备。除网络设备外,字符设备和块设备都被映射到Linux文件系统和目录,通过文件系统的系统调用接口open()、write()、read()、close()等函数即可访问。块设备会想对比较复杂,在它上面会首先建立一个磁盘/Flash文件系统,如FAT、EXT3、YAFFS、JFFS等,这些规范了文件和目录在存储介质上的组织。应用程序可以调用
Linux的系统调用接口编程也可以使用C库函数。
在设备驱动中会大量的使用自旋锁、互斥、信号量、等待队列等并发与同步机制。有良好的硬件基础、C语言基础、Linux内核基础。
网络设备驱动:使用的是socket文件,而不以/dev下的设备文件为接口。
Linux的网卡驱动程序处于OSI模型中的数据链路层。职责是将上上层的协议栈传过来的消息通过网卡发送出去。
网络设备驱动的注册与注销由register_netdev()和ungister_netdev()函数完成。
网络设备初始化:硬件的准备工作,检测网络设备和硬件资源。软件的准备工作,分配net_device结构体并对齐数据和函数指针成员赋值。获得设备的私有信息指针并初始化各成员的值,如果私有信息包含自旋锁或信号量等并发或同步机制,则需进行初始化。

两个结构体:
sk_buff结构体:就是socket缓冲区,是流经网络栈内部的结构体,负责在源和汇点之间传递报文数据。
net_device_ops结构体:网络设备的一系列硬件操作行数的集合,网络设备接口层内部。

网络协议接口层,网络设备接口层,设备驱动功能层,网络设备与媒介层。
网络协议接口层使用的接口不管是什么协议都通过dev_queue_xmit()函数发送数据,通过netif_rx()函数接收数据。
网络设备接口层结构体为net_device。
设备驱动功能层使用的接口用函数hard_start_xmit()函数发送数据包,由中断处理来进行数据包的接收。


网络设备的打开和释放:
打开网络设备:使能设备使用的硬件资源,申请I/O区域,中断和DMA通道等,调用linux内核提供的netif_start_queue()函数,激活设备发送队列。
关闭网络设备:调用netif_stop_queue()函数,停止设备传输包,释放设备所使用的I/O驱动,中断和DMA资源。


linux网络子系统在发送数据包时会调用驱动程序提供的hard_start_transmit()函数,用于启动数据包的发送。在设备初始化的时候函数指针需被初始化指向设备的xxx_rx()函数。


数据包的发送流程:网络设备驱动程序从上层协议传递过来的sk_buff参数获得数据包的有效数据和长度,将
有效数据放入临时缓冲区。对于以太网,如果有效数据的长度小于以太网冲突检测的最小长度ETH_ZLEN,则给
临时缓冲区的末尾填充0。设置硬件寄存器,驱使网络设备进行数据发送操作。
网络设备的数据接收流程:网络设备接收数据的主要方法是由中断引发设备的中断处理函数,中断处理函数判
断中断类型,如果为接收中断,则读取接收到的数据,分配sk_buffer数据结构和数据缓冲区,将接收到的数
据复制到数据缓冲区,并调用netif_rx()函数将sk_buffer传递给上层协议。
网络连接状态:网络适配器硬件电路可以检测出链路上是否有载波,载波反映了网络的连接是否正常,网络设
备驱动可以通过netif_carrier_on()和netif_carrier_off()函数改变设备的连接状态,如果驱动检测到设备
的连接状态发生变化可以用以上两个函数显示的通知内核。函数netif_carrier_ok()可用于想调用者返回链路
上的载波信号是否存在。

中断处理:新报文到达中断、报文发送完成中断、出错中断。中断处理程序可以通过查看网卡的中断状态寄存
器, 来分辨出中断类型。中断是指在CPU正常运行期间,由于内外部事件或程序预先安排的事件引起的CPU暂
停正在运行的程序转去中断的程序。外部中断叫硬件中断,内部中断叫异常。
中断请求概述:外部设备当需要操作系统做相关的事情的时候,会产生相应的中断。0-31号中断被系统保留,
共剩下32-255共224个中断向量可用。由于外设很多而中断线很宝贵,因此在使用中断线前需要对相应的中断
线进行申请。无论是共享中断还是独占一个中断,申请过程都是先将所有的中断线进行扫描,得出哪些没被占
用并从中选出一个作为该设备的IRQ。其次,通过中断申请函数申请相应的IRQ,最后根据申请结果查看中断能
否被执行。


可以把中断处理机制分为两部分执行上半部分是中断处理程序,处理紧急的中断,如当网卡收到数据包时通知
内核触发中断,及时读取数据包到内存,防止因为延迟导致丢失。而读取到内存后不再那么紧迫,就可以执行
中断前运行的程序,而对网络包的处理交给下半部分处理。
上半部分中断用于处理:1.对时间敏感,2.和硬件有关,3.要保证不被其他中断打断。
下半部分实现机制有软中断和工作队列,软中断用于处理上半部的剩余任务,是可延迟函数的总称,可以在多
个CPU上并发运行,因此软中断必须设计为可重入函数(允许多个CPU同时操作),同时也要用自旋锁来保护其数
据结构。


工作队列可休眠,可被阻塞,也能进行进程切换,工作队列的函数由内核函数实现,不能访问用户空间。

GDT全局描述表
实时模式内存地址访问是通过Segment:Offset,就是一个内存绝对地址。在实际编程时使用16-bit段寄存器CS代码段,DS数据段,SS堆栈段来制定segment,CPU将段寄存器中的数值向左偏移4-bit,放到20-bit的地址线上就成为20-bit的Base Address。
到了保护模式,内存的管理模式分为段模式和页模式。
GDT用于存储段描述符以及一些其他描述符,Intel的设计者提供了一个寄存器GDTR来存放GDT的入口地址
LDT是针对引用它们的任务可见的,在系统中可以存在多个,也有一个寄存器LDTR来存储。
实模式下对于内存的保护不是特别的完善,一个段可以任意访问不是该段范围内的内存。是很危险的,因此引入了保护模式。保护模式下的段访问在访问之前就已经注册好了段偏移量。在全局描述符中进行注册。寄存器GDTR全局描述符为6字节,高32位为全局描述符基址,低16位为全局描述符界限。

引用:
https://blog.csdn.net/viewsky11/article/details/54933057

网络协议接口层:
数据包发送dev_queue_xmit()//从协议层向设备中发送sk_buff,就需要使用dev_queue_xmit函数,这个函数
可以对sk_buff进行排队,从而由底层设备驱动程序进行最终传输。使用sk_buff中引用net_device,dev结构
中包含了一个名为hard_start_xmit的方法,其中保存有发起sk_buff传输所使用的驱动程序函数。
数据包接收netif_rx()//当设备底层驱动接收一个报文,netif_rx将sk_buff上传至网络层。然后这个函数通
过netif_rx_schedule将sk_buff在上层协议队列中进行排队,供以后进行处理。
网络设备接口层:结构体net_device
设备驱动功能层:数据包发送hard_start_xmit(),中断处理(数据包接收)
网络设备与媒介层:网络物理设备媒介

用户态可以通过系统调用、异常、外围设备中断切换到内核态。
注册过中断的外围设备当完成了程序赋予的任务后会向系统发送中断信号,此时CPU将停止执行下一条语句而进行跳转执行中断处理程序,此时系统陷入内核态。
异常可能如缺页异常等。
用户态主动切换至内核态如fork、read、write、ioctl等。

相关函数总结:
1.int socket(int domain,int type,int protocal)
domain:AF_INET、AF_INET6、AF_LOCAL等;
type:SOCK_STREAM(TCP)、SOCK_DGRAM(UDP)、SOCK_RAW(原始套接字)
protocal:一般为0

2.int bind(int sockfd,const struct sockaddr* myaddr,socklen_t addrlen)

使用:
int main(int argc, char *argv[])
{
    int sockfd; //套接字文件描述符变量
    struct sockaddr_in my_addr; //以太网套接字地址结构

    sockfd = socket(AF_INET, SOCK_STREAM, 0); //初始化socket
    if (sockfd == -1) {
    peeror("socket"); //检查是否正常初始化socket
    exit(EXIT_FAILURE);
    }
    my_addr.sin_family = AF_INET; //地址结构的协议族
    my_addr.sin_port = htons(MYPORT); //地址结构的端口地址,网络字节序
    my_addr.sin_addr.s_addr = inet_addr("192.168.1.2"); //IP,将字符串的IP地址转化为网络字节序
    bzero(&(my_addr.sin_zero), 8); //将my_addr.sin_zero置为0
    if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1) { // 判断是否绑定成功
    perror("bind");
    exit(EXIT_FAILURE);
    }
    ... //接收和发送数据,进行数据处理
    close(sockfd); //关闭套接字文件描述符
}

3.int listen(int sockfd,int backlog)
函数listen仅被TCP服务调用
backlog参数为内核为此套接口排队的最大连接个数。
对于给定的监听套接口,内核要维护两个队列:
1.未完成连接队列,为每个这样的SYN分节开设一个条目:已由客户发出并到达服务器,服务器正在等待完成相应的TCP三路握手过程。这些套接口处于SYN_RCVD状态。
2.已完成连接队列,为每个已完成TCP三路握手过程的客户开设一个条目,这些套接口都处于ESTABLISHED状态。
两个队列之和数量不得超过backlog。

4.int connect(int sockfd,const struct sockaddr *addr,socklen_t addrlen)
对于TCP此函数是发起三次握手;UDP则是让内核记录对方的ip和端口号,他们包含在传递给connect的套接字地址结构中,并立即返回给调用进程。

5.int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen)
从已完成队列头中返回下一个已完成连接。若已完成连接队列为空,则进程睡眠(假定套接口为缺省的阻塞方式)

6.size_t send(int sockfd,const void *buf,size_t len,int flags)

7.size_t recv(int sockfd,void *buf, size_t len,int flags)


TCP拥有一个发送缓冲区,而UDP没有,因为UDP是不可靠连接不必保存应用进程的数据拷贝,应用进程中的数据在沿协议栈向下传递时以某种形式拷贝到内核缓冲区,当数据链路层把数据传出后就把内核缓冲区的中的数据拷贝删除。sendto和write表示应用程序的数据或数据分片已经进入链路层的输出队列,如果输出队列没有足够的空间则返回ENOBUFS。每个TCP都有一个发送缓冲区,它的大小可以用SO_SNDBUF这个选项来改变,调用send函数的过程实际是内核将用户数据拷贝至TCP套接口的发送缓冲区的过程;若len大于发送缓冲区大小则返回-1,否则查看缓冲区剩余空间是否容纳的得下要发送的len长度。
TCP缓冲区只有在接受到对方的ACK以后才会清空缓冲区。

内核将用户数据拷贝至TCP套接口的发送缓冲区。
而UDP用的是内核缓冲区。
他们要分片去到数据链路层的输出队列。如果数据链路层的输出队列没有足够的空间会返回一个ENOBUFS错误。
同样的recv和recvfrom是从接收缓冲区接收数据,

sockfd
struct sockaddr *addr        socklen_t *addr_len
const void *buf            size_t len

sendto :
const void *buf,size_t len,int flags,const struct sockaddr *dst_addr,socklen_t addrlen

recvfrom :
const void *buf,size_t len,int flags,struct sockaddr *src_addr,socklen_t *addrlen

 

OAuth中的三种认证方式,资源所有者密码凭据许可,隐式许可,授权码许可。
session是空间换时间,token是时间换空间。
token中间可以有一层Authorization层,用于将认证中心的Authorization Code传回给hash fragment。也就
是网址后面那个#号后面的内容,由于token是明文,因此用code去获取token可以使token获取解析服务全部在
后台搞定而不会反映到前端界面。token就是指重定向跳转至授权服务器后的资源服务器本身的页面,就相当
于是一种登陆中转,这样平台不会获取到用户的个人信息。
token是对身份信息的加密,只需要通过解密就可以判断是不是自己人。而session一定要通过后台的验证,需
要占用服务器后台资源,session过多很明显会降低性能。
token一般存储在缓存或数据库中,以便后面查询验证。还需要打上时间戳,在一定时间内会过期。
常使用的加解密算法有3DES与RSA。每次发起请求需要带上token。
单点登陆SSO,指一个服务器登陆以后需要让其他同类归属这家公司的服务器都可以识别这个id,单点登陆有一个难点,也就是跨域问题,同一顶级域名下的情况还好说但完全不同的域名则难以实现。解决办法:在SSO中维护一个分站集合,在登陆成功以后以轮询跳转的方式将cookie依次写到各个分站中。登陆成功后将用户信息保存在session中,sessionId保存在cookie中。

linux查看当前服务器在线连接数:netstat -na|wc -l
有效连接数:netstat -nat|grep ESTABLISHED|wc -l
top查看本机进程内存等信息


redis的五种数据结构:
string字符串,list列表,set集合,sorted set有序集合,hash字典
redis的pub/sub功能,可以对一个key进行消息发布后,所有订阅它的客户端都会收到消息
redis的transactions,虽然不是严格的ACID事务,但是具有基本的命令打包执行的功能
redis的watch功能,可以对一个key进行watch再执行transactions,如果过程中被watch的值进行了修改,那
么Transactions会发现并拒绝执行。
String配合GET、SET的使用以及原子计数器。
Hah存取、读取、修改用户的属性。
List最新消息排行以及消息队列,就理解为是一个链表(双端链表)
set是具有唯一性的,可以统计网站的独立IP,用交集并集差集等进行共同好友、二度好友的查找。
sorted set给set中的元素添加了一个权重参数score,因此能够按照score进行有序排列,可以求得一个游戏
的用户得分榜。


XA协议,作为资源管理器(数据库)与事务管理器的接口标准。目前各大数据库厂家都支持XA协议,而事务管理器负责各个本地资源的提交和回滚。XA协议采用两阶段提交方式来管理分布式事务。消息中间件也称做消息系统(MQ),本质是一个暂存转发消息的一个中间件。分布式应用中我们将一个业务操作转换为一个消息,比如支付宝余额转入支付宝,支付宝减少余额后向消息系统发一个消息,余额宝订阅这条消息然后进行增加账户金额操作。
消息处理模型具有点对点和发布订阅机制。
消息的可靠性:
发送端完成操作消息后一定能把消息成功发送到消息系统。可以通过在本地数据建一张消息表,业务完成即进行消息发送。消息发送成功后就删除消息表中的数据,否则继续重传。接收端仅且能够从消息中间件成功消费一次消息。使逻辑具有幂等性,使用一张日志表,记录并保证消息具有唯一编号。

负载均衡算法:轮询、加权轮询、最少连接、加权最小连接、随机
分布式锁:
基于MySQL锁表,获得锁则插入一条记录而释放锁就删除这条记录,乐观锁版本号。
基于Redis锁,有SETNX(set if not exist,key-value类,如果已存在则插入该记录则返回false)和EXPIRE(过期时间,避免死锁)。
Zookeeper分布式锁???

由于分布式出现的session问题。
1.粘性session,指将用户锁定到某一个服务器上。
2.服务器session复制,将自己session内容序列化广播出去。可以在Tomcat的server.xml开启Tomcat集群功能。
3.session共享机制,粘性session共享是指将用户session绑定到Tomcat上,Memcached实现备份。非粘性session共享机制,Tomcat本身不存储Session,而是存入Memcached中,Memcached集群构建主从复制架构。有插件Memcached_Session_Manager实现。
4.session持久化到数据库。

主从和集群:集群是data-sharing,主从是nothing-sharing,主从使用来建立一个和主数据库一样的数据库环境。
作用:做数据的热备,架构的扩展(降低磁盘IO的访问频率),读写分离使数据库能支持更大的并发(如果前台使用master、报表使用slave,这样就可以保证速度)
过程:主库bin-log输出线程、从库I/O线程、从库SQL线程写入relay-log文件。还有增量式读取。
MySQL 3306端口
TCP   443端口

线程池线程数:如果是I/O密集型则线程数为2倍的CPU数。如果是CPU密集型则设置CPU数加一就可以了。更多的线程数只能增加上下文切换,不能增加CPU的利用率。精确控制需要根据上线后观察情况而定。

vfptr是一个虚表指针,这个指针指向父类函数。继承自一个父类就会有一个虚表指针。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值