Linux内核启动(1,0.11版本)启动BIOS与加载内核
从电源到启动BIOS
从我们按下启动电源到BIOS,按下电源–>主板会向电源组发出信号–> 接受到信号后,当主板收到电源正常启动信号后,主板会启动CPU(CPU重置所有寄存器数据,并且初始化数据),比如32位系统,实模式采用内存段来管理0-0xFFFFF这1MB内存空间。
实模式:内存访问是真实的内存地址,软件可以不受限制操作实际内存所有地址空间和IO设备)
保护模式:全部使用虚拟内存,页等机制对内存进行保护,比起实模式更为安全和可靠,同时也增加了扩展性和灵活性
计算机的运行是离不开程序的,但是CPU被设计的智能读取内存中的程序和数据,不能直接从硬盘加载程序和数据,必须先将程序和数据加载到内存,那我们怎么启动程序呢,秘诀是 0xFFFF0
,既然软件的方式无法执行BIOS,那我们就采取硬件的方式,从硬件的角度看,8086系列CPU可以分别在16位实模式和32位保护模式运行,为了兼容也为了解决最初的启动问题,Intel将所有的x86系列CPU包括最新的CPU硬件都设计为加电即进入16位实模式运行,当然,关键的是将CPU的硬件逻辑设计为加电瞬间强行将CS寄存器的值设置为 0xF000
IP寄存器的值设置为 0xFFF0
这样CS:IP就指向了 0xFFFF0
这个地址位置
CS是代码段寄存器,IP是指令指针寄存器,两者组合就是即将要执行的指令的内存地址,实模式为绝对地址,指令指针为16位,保护模式下为线性地址,指令指针为32位即EIP,
实模式下两者组合出线性地址的方式为
CS << 4 + IP
注意,这是一个纯硬件操作,如果 0xFFFF0
处没有任何可执行代码,那么CPU就此死机,但是BIOS程序的第一条指令就设计在这个位置
BIOS程序的代码量并不大,但是却非诚精深,需要对计算机硬件非常熟悉才能看明白,这显然已经超出了 Linux 的范围,所以只做简单讲解,BIOS程序被固化在计算机主板上一块非常小的ROM内,通常不同主板采用的BIOS也不同,但是其基本原理大致相同,当屏幕开始显示时,这意味着BIOS已经启动了,有一项对启动操作系统至关重要的工作,就是BIOS在内存中建立中断向量表和中断服务程序。
ROM 只读存储器,断电之后仍能保存信息,但是某些情况下因为BIOS是写在闪存上的,所以也可以更改,毕竟BIOS也是可以升级的。
BIOS程序在内存最开始的位置用1KB构建中断向量表,用256字节构建BIOS数据区,在大约57KB之后的位置,加载了8KB左右的与中断向量表相应的若干中断服务程序。此时内存的分布
内存位置 | 内容 |
---|---|
0x00000 - 0x003FF | 中断向量表 |
0x00400 - 0x004FF | BIOS数据区 |
0x00500 - 0x0E05A | 空 |
0x0E05B - 0x0FFFE | 中断服务程序 |
0x0FFFF - 0xFFFEF | 空 |
0xFE000 - 0xFFFFF | BIOS启动块 |
我们可以发现,其实0xFFFF0并不是BIOS启动块的头地址,只是BIOS的第一行程序的地址。
中断(INT),打断正在执行的程序,转而执行处理这个时间的特定程序,处理结束后,回到被打断的程序继续执行,可以理解为一种技术手段
加载操作系统内核
现在开始我们要加载操作系统内核了,但是我们发现一个问题没有,我们操作系统内核还是在硬盘或者软盘上,没有在内存里啊,这个其实也是硬件完成的,BIOS启动之后,计算机完成自检,我们把我们的软盘设置成了启动设备,所以计算机硬件和BIOS程序会联手操作,让CPU收到一个 int 0x19
中断,CPU收到这个中断后,会立即在中断向量表中找到这个中断向量,然后中断向量吧CPU指向 0x0E6F2
这个位置,这个位置就是对应的中断服务程序的入口地址,这个中断是设计好的,代码是固定的,与我们的操作系统无关,这段代码唯一的作用就是找到软盘加载第一扇区,其余的它什么都不知道,也不必知道。
中断向量表(interrupt Vector Table):实模式中断机制的重要组成部分,记录所有的中断号对应的中断服务程序内存地址
中断服务程序(interrupt Service Programme):通过中断向量表的索引对中断进行响应服务,是一些具有特殊功能的程序
按照这个规则,int 0x19
中断将软盘的0号磁头对应的盘面的0磁道1扇区的内容复制到 0x07C00
的位置,这个数据块有多大呢,512B,这个扇区内装载的就是Linux 0.11的引导程序,也就是我们要讲的 bootsect.s
程序,这是一个汇编程序。此时我们就有了我们操作系统自己的代码了,虽然只是启动代码。此程序的源文件地址位于 /boot/bootsect.s
bootsect
的功能很简单,就是把第二批和第三批程序陆续加载到内存,为了能加载到适当位置,bootsect
首先做的就是规划内存。要知道,实模式下的内存寻址最大范围是1MB,内存是非常宝贵的。
这里我们就涉及到Linux的内核源码了,接着看
SYSSIZE = 0x3000 ! 给出system模块的大小 0x3000字节 = 192KBSETUPLEN = 4 ! setup程序的扇区数
BOOTSEG = 0x07c0 ! bootsect的起始地址
INITSEG = 0x9000 ! bootsect的目标地址
SETUPSEG = 0x9020 ! setup的起始地址
SYSSEG = 0x1000 ! system的起始加载地址
ENDSEG = SYSSEG + SYSSIZE ! system的终止地址! ROOT_DEV: 0x000 - same type of floppy as boot.
! 0x301 - first partition on first drive etc 指定根文件系统设备时第2个硬盘的第一个分区
ROOT_DEV = 0x306
这里定义了一些数据,目的是规划内存
entry _start
_start:mov ax,#BOOTSEGmov ds,axmov ax,#INITSEGmov es,axmov cx,#256sub si,sisub di,direpmovwjmpi go,INITSEG
这里进入第一个函数 _start
,这个函数的目的就是想 0x07C00
处的引导程序搬到 0x90000
处,在这次复制过程中,DS和SI联合使用构成了原地址 0x07C00
,ES和DI联合使用构成了目标地址 0x90000
,而给CX赋值 256
的原因是 movw这个指令复制的是字,一个字为两个字节,256个字刚好为512字节,rep反复执行movw直到CX为0,执行完毕后执行跳转指令
ENTRY 是程序入口伪指令。在一个完整的汇编程序中至少有一个 ENTRY,编译程序在编译连接时依据程序入口进行连接
go: mov ax,csmov ds,ax ! 数据段寄存器mov es,ax ! 附加段寄存器
! put stack at 0x9ff00. mov ss,ax ! 栈寄存器 栈操作是从高地址到低地址mov sp,#0xFF00 ! arbitrary value >>512
这里使用CS初始化段寄存器和栈空间,就比较简单了,此时CS段寄存器的地址是 0x9000
,所以DS,ES,SS都被赋值为 0x9000
,这其实意味着我们可以使用栈了,也意味着我们可以使用13号中断来从磁盘搬运程序了,接着往下走
load_setup:mov dx,#0x0000 ! drive 0, head 0mov cx,#0x0002 ! sector 2, track 0mov bx,#0x0200 ! address = 512, in INITSEGmov ax,#0x0200+SETUPLEN ! service 2, nr of sectorsint 0x13 ! read it jnc ok_load_setup ! ok - continuemov dx,#0x0000 ! mov ax,#0x0000 ! reset the disketteint 0x13 j load_setup
0x13
中断是一个服务,用来对磁盘进行操作,我们介绍一下各寄存器的功能,如果要使用这个功能,需要
AH
:必须设置为0x02
AL
:扇区数目
CH
:柱面
CL
:扇区
DH
:磁头
DL
:驱动器(00H - 7FH 为软盘;80H - 0FFH 为硬盘)
ES:BX
: 缓冲区地址
既然是读取操作必然要制导读取结果,如果 CF=0
则表示成功,此时 AH=状态码
,AL=传输的扇区数
此时ES = 9000H
,而读取时BX = 0x0200
,所以读取后被放到0x90200
这个地址。如果读取成功,就会跳转到ok_load_setup
这个标签,失败重置磁盘状态(AH = 0
调用),重试直到成功。执行完int 0x13
指令后,我们看看下面的程序:
ok_load_setup:! Get disk drive parameters, specifically nr of sectors/trackmov dl,#0x00 ! DL 为驱动器 如果成功CF= 0 BL会获得1-4的数据,为磁盘大小mov ax,#0x0800 ! AH=8 is get drive parameters AH= 8 时是获取磁盘信息int 0x13 ! mov ch,#0x00 seg csmov sectors,cxmov ax,#INITSEGmov es,ax
当AH = 0x08
时,调用int 0x13
指令是获取磁盘大小信息,其中DL
为驱动器,如果成功CF = 0
,BL
会获得1-4
的数值,含义如下
BL=1
360KB
BL=2
2.2MB
BL=3
720KB
BL=4
1.44MB
与此同时,一些其他寄存器也被赋予了含义
CH
代表柱面数的低八位
CL
的高两位代表柱面数的高两位,低六位代表扇区数
DH
代表柱头数
DL
代表驱动器数
ES:DI
指向的是磁盘驱动器参数表地址
seg cs
只影响到mov sectors,cx
而不影响mov ax,#INITSEG
,如果以Masm语法写,seg cs
和mov sectors,cx
两句合起来等价于mov cs:[sectors],cx
,这里使用了间接寻址方式。seg cs
只是表明紧跟它的下一条语句将使用段超越,因为在编译后的代码中可以清楚的看出段超越本质上就是加了一个字节的指令前缀。cx
的高八位已经被置为0,所以这里是将区块的扇区数目放到了CS:sectors
这个地址中。
! Print some inane messagemov ah,#0x03 ! read cursor posxor bh,bhint 0x10 mov cx,#24mov bx,#0x0007 ! page 0, attribute 7 (normal)mov bp,#msg1mov ax,#0x1301 ! write string, move cursorint 0x10
这段代码中的 int 0x10
中断用于向屏幕中输出字符串,这一段代码将 msg1
输出到了屏幕上
msg1: ! "\nLoading system ...\n".byte 13,10.ascii "Loading system ...".byte 13,10,13,10
msg1
写的是 "Loading system ..."
,回车键的ASCII
是13,换行键的ASCII
是10,如果组合起来就是回车换行,就是C/C++
的\n
我们继续下面的代码
! ok, we've written the message, now
! we want to load the system (at 0x10000)mov ax,#SYSSEGmov es,ax ! segment of 0x010000call read_itcall kill_motor
这部分就是加载system
模块了,system
模块就是内核模块,包含库模块lib
、内存管理模块mm
、内核模块kernel
、main.c
和head.s
程序,后面将会详细介绍。read_it
就是读取函数,将模块读取到0x010000
这个地址。kill_motor
函数是关闭驱动器马达,以知道驱动器状态。
从底层技术上看,这与前面的setup程序加载没什么本质区别,比较突出的特点是,这次加载的扇区数是240个,足足是之前加载4个扇区的60倍,所需时间也是几十倍的增加,为了防止用于以为是机器故障,所以才有了之前的往屏幕上输出一个字符串的操作。
我们先看read_it
,这个函数的功能是把软盘第六扇区看事的约240个扇区的system
模块加载到内存的SYSSEG(0x10000)
处,由于长时间的操作软盘,所以对软盘设备需要更多地监控,对读盘结果需要不断地检测,因此read_it
后续的调用步骤多一点
sread: .word 1+SETUPLEN ! sectors read of current track
head: .word 0 ! current head
track: .word 0 ! current trackread_it:mov ax,estest ax,#0x0fff
die: jne die ! es must be at 64kB boundaryxor bx,bx ! bx is starting address within segment
rp_read:mov ax,escmp ax,#ENDSEG ! have we loaded all yet?jb ok1_readret
ok1_read:seg csmov ax,sectorssub ax,sreadmov cx,axshl cx,#9add cx,bxjnc ok2_readje ok2_readxor ax,axsub ax,bxshr ax,#9
ok2_read:call read_trackmov cx,axadd ax,sreadseg cscmp ax,sectorsjne ok3_readmov ax,#1sub ax,headjne ok4_readinc track
ok4_read:mov head,axxor ax,ax
ok3_read:mov sread,axshl cx,#9add bx,cxjnc rp_readmov ax,esadd ax,#0x1000mov es,axxor bx,bxjmp rp_readread_track:push axpush bxpush cxpush dxmov dx,trackmov cx,sreadinc cxmov ch,dlmov dx,headmov dh,dlmov dl,#0and dx,#0x0100mov ah,#2int 0x13jc bad_rtpop dxpop cxpop bxpop axret
bad_rt: mov ax,#0mov dx,#0int 0x13pop dxpop cxpop bxpop axjmp read_track
嗯,是不是乱的一批,其实没有太多的必要去理解这个代码,这个和硬件的关系太紧密了,我们只需要知道这里搬运了一部分代码就可以了。
此时只剩下了最后一块bootsect.s
程序:
! After that we check which root-device to use. If the device is
! defined (!= 0), nothing is done and the given device is used.
! Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending
! on the number of sectors that the BIOS reports currently.seg csmov ax,root_devcmp ax,#0jne root_definedseg csmov bx,sectorsmov ax,#0x0208 ! /dev/ps0 - 1.2Mbcmp bx,#15je root_definedmov ax,#0x021c ! /dev/PS0 - 1.44Mbcmp bx,#18je root_defined
undef_root:jmp undef_root
root_defined:seg csmov root_dev,ax
root_dev
是一个变量,它指向一个字大小的宏ROOT_DEV
,它的值为0x306
。
root_dev:.word ROOT_DEV
为什么是这个值呢?如果该值为0
,根文件系统设备与引导使用同样的软驱设备;如果是0x301
,则为第一个硬盘的第一个分区上,这个被称为设备号。设备号 = 主设备号 * 256 + 次设备号
设备号 | 设备文件 | 对应的设备 |
---|---|---|
0x300 | /dev/hd0 | 系统中第一个硬盘 |
0x301 | /dev/hd1 | 系统中第一个硬盘的第一分区 |
0x302 | /dev/hd2 | 系统中第一个硬盘的第二分区 |
0x303 | /dev/hd3 | 系统中第一个硬盘的第三分区 |
0x304 | /dev/hd4 | 系统中第一个硬盘的第四分区 |
0x305 | /dev/hd5 | 系统中第二个硬盘 |
0x306 | /dev/hd6 | 系统中第二个硬盘的第一分区 |
0x307 | /dev/hd7 | 系统中第二个硬盘的第二分区 |
0x308 | /dev/hd8 | 系统中第二个硬盘的第三分区 |
0x309 | /dev/hd9 | 系统中第二个硬盘的第四分区 |
这一部分就是再次确认一下根设备号
Linux 0.11使用的文件系统管理方式要求系统必须存在一个根文件系统,其他文件系统挂接在骑上,而不是同等地为,Linux 0.11 并没有提供在设备上建立文件系统的工具所以必须在一个正在运行的系统上利用工具作出一个文件系统并加载至本机,所以Linux 0.11 的启动需要分为两部分,内核镜像和根文件系统。
于是该内核使用的是第二个硬盘的第一个分区,作为根文件系统设备。接下来两个cmp
可能看不懂,咱们给个解释:sectors
是我们之前保存的每磁道扇区数目,如果是 15 ,那么就是 1.2 MB 的驱动器;如果是 18 ,那么就是 1.44 MB 的,也就是引导驱动器的设备号。如果正常找到,将会执行jmpi 0,SETUPSEG
,该部分程序结束;否则,直接死循环。
跳转到setup
跳转到setup就简单多了,随便的一行
! after that (everyting loaded), we jump to
! the setup-routine loaded directly after
! the bootblock:jmpi 0,SETUPSEG
总结
本文主要讲了从按下电源按钮的那一刻,到将操作系统加载到内存中主要发生了什么,这也是这一个系列的第一个部分的第一章。
相关文章:
Linux内核启动(1,0.11版本)启动BIOS与加载内核
从电源到启动BIOS 从我们按下启动电源到BIOS,按下电源–>主板会向电源组发出信号–> 接受到信号后,当主板收到电源正常启动信号后,主板会启动CPU(CPU重置所有寄存器数据,并且初始化数据),比如32位系统ÿ…...
python制作贪吃蛇小游戏,畅玩无限制
前言 大家早好、午好、晚好吖 ❤ ~ 现在这年头,无论玩个什么游戏都有健康机制, 这让我们愉悦玩游戏得步伐变得承重起来, 于是无聊之下我写了个贪吃蛇小游戏,来玩个快乐 代码展示 导入模块 import random import sys import …...
MySQL-InnoDB数据页结构浅析
在MySQL-InnoDB行格式浅析中,们简单提了一下 页 的概念,它是 InnoDB 管理存储空间的基本单位,一个页的大小一般是 16KB 。 InnoDB 为了不同的目的而设计了许多种不同类型的 页: 存放表空间头部信息的页存放 Insert Buffer信息的…...
Java、JSP职工人事管理系统设计与实现
技术:Java、JSP等摘要:现在随着我们这个社会的计算机技术的快速发展,计算机在企业管理中得到普遍的应用,现在我们利用计算机在实现企业职工的管理越来越重要。当今社会是快速发展的信息社会,自动化信息的作用也变得越来…...
数据结构与算法这么难,为什么我们还要学习?
文章目录前言1. 数据结构与算法是什么?2. 为什么数据结构与算法很难?3. 如何系统学习数据结构与算法?🍑 复杂度🍑 线性表🍑 树形结构🍑 图🍑 排序🍑 字符串🍑…...
剑指 Offer 52. 两个链表的第一个公共节点
摘要 剑指 Offer 52. 两个链表的第一个公共节点 一、双指针解法 使用双指针的方法,可以将空间复杂度降至 O(1)。只有当链表 headA headB都不为空时,两个链表才可能相交。因此首先判断链表 headA和 headB是否为空,如果其中至少有一个链表为…...
可以写进简历的软件测试电商项目,不进来get一下?
前言 说实话,在找项目的过程中,我下载过(甚至付费下载过)N多个项目、联系过很多项目的作者,但是绝大部分项目,在我看来,并不适合你拿来练习,它们或多或少都存在着“问题”ÿ…...
蓝桥杯-算法-印章问题
这个题真的顶啊!思路:n种图案,m张印章,每一个图案的概率是1/n,这个概率以后用P表示首先我们定义dp[i][j]是买了i张印章(对应于上面的m),凑齐j种图案的概率(对应于上面的n…...
戴尔游匣G16电脑U盘安装系统操作教程分享
戴尔游匣G16电脑U盘安装系统操作教程分享。有用户在使用戴尔游匣G16电脑的时候遇到了系统问题,比如电脑蓝屏、自动关机重启、驱动不兼容等问题。遇到这些问题如果无法进行彻底解决,我们可以通过U盘重新安装系统的方法来解决,因为这些问题一般…...
2023数学建模美赛赛题思路分析 2023美赛 美国大学生数学建模数模
将在本帖更新2023美国大学生数学建模数模美赛各个赛题思路,大家可以点赞收藏! 一、参赛报名 组队参赛(每队人数3人,专业不限)。 二、赛题思路及资料 会在本帖更新思路分析,Q群可领取模型代码/赛题思路资料…...
vue3与vue2的对比
Vue 3.0 和 Vue 2.0 是 Vue 前端框架的两个主要版本,它们有着不同的更新和优化: Vue 3.0 主要更新内容: 采用 TypeScript 作为开发语言,提高了代码的类型安全性。 速度更快,内存使用更少,支持大规模数据处…...
史上最全软件测试工程师常见的面试题总结(百度、oppo、中软国际、华为)备战金三银四
1、面试:神州数码1.介绍你下你项目中一个自动化实现的流程2.你觉得做自动化的意义在哪里 >需要对之前已经实现的功能进行回归测试、保证当前版本更新的内容不能影响到之前已经实现好的功能3.你们做自动化产生了什么结果 >测试报告、报错截图和报错日志、测试报…...
“深度学习”学习日记。卷积神经网络--用CNN的实现MINIST识别任务
2023.2.11 通过已经实现的卷积层和池化层,搭建CNN去实现MNIST数据集的识别任务; 一,简单CNN的网络构成: 代码需要在有网络的情况下运行,因为会下载MINIST数据集,运行后会生成params.pkl保留训练权重&…...
JavaWeb--JDBC练习
JDBC练习5.1 需求5.2 案例实现5.2.1 环境准备5.2.2 查询所有5.2.3 添加数据5.2.4 修改数据5.2.5 删除数据5.1 需求 完成商品品牌数据的增删改查操作 查询:查询所有数据添加:添加品牌修改:根据id修改删除:根据id删除 5.2 案例实…...
【LeetCode】2335. 装满杯子需要的最短总时长
2335. 装满杯子需要的最短总时长 题目描述 现有一台饮水机,可以制备冷水、温水和热水。每秒钟,可以装满 2 杯 不同 类型的水或者 1 杯任意类型的水。 给你一个下标从 0 开始、长度为 3 的整数数组 amount ,其中 amount[0]、amount[1] 和 a…...
Android 12.0 通过驱动实现禁用usb鼠标和usb键盘功能
1.1概述 在12.0的系统产品定制化开发中,在进行定制中有关于usb键盘和usb鼠标的需求中,产品要求禁止usb口挂载usb鼠标和usb键盘,所以需要要求在usb挂载类型的时候 判断如果是usb鼠标和usb键盘就不让挂载,这就需要从驱动方面入手来解决这个问题,接下来看下驱动的某些挂载usb…...
C++入门——内存管理
C入门——内存管理 C/C内存分布 分类是为了更好的管理 int globalVar 1; static int staticGlobalVar 1; void Test() {static int staticVar 1;int localVar 1;int num1[10] {1, 2, 3, 4};char char2[] "abcd";char* pChar3 "abcd";int* ptr1 (…...
MySQL-InnoDB行格式浅析
简介 我们知道读写磁盘的速度非常慢,和内存读写差了几个数量级,所以当我们想从表中获取某些记录时, InnoDB 存储引擎需要一条一条的把记录从磁盘上读出来么? 不,那样会慢死,InnoDB 采取的方式是:…...
AXI 总线协议学习笔记(4)
引言 前面两篇博文从简单介绍的角度说明了 AXI协议规范。 AXI 总线协议学习笔记(2) AXI 总线协议学习笔记(3) 从本篇开始,详细翻译并学习AXI协议的官方发布规范。 文档中的时序图说明: AXI指࿱…...
C++复习笔记6
1.String类的实现 注意深浅拷贝, C语言字符串拼接函数strcat() #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<vld.h> #include<assert.h> using namespace std;class String {friend ostream& operator<<(ostream &am…...
指针的步长及意义(C语言基础)
指针的步长及意义 文章目录指针的步长及意义指针变量1后偏移的字节数不同指针解引用时取出的字节数不同其他例子不同类型的指针有何不同的意义指针变量1后跳跃字节数量不同解引用的时候,取出字节数量不同 指针变量1后偏移的字节数不同 代码演示:&#…...
SpringMVC:统一异常处理(11)
统一异常处理1. 说明2. 问题描述3. 异常处理器使用3.1 创建异常处理器类3.2 让程序抛出异常3.3 测试4. 项目异常处理方案4.1 异常分类4.2 异常解决方案4.3 异常解决方案的具体实现4.4 测试5. 总结1. 说明 \quad本篇文章是在文章SpringMVC:SSM整合(Spring…...
SpringBoot的配置与使用
SpringBoot简介 我们的Spring是包含了众多工具的IoC容器,而SpringBoot则是Spring的加强版,可以更加方便快捷的使用 如果Spring是手动挡的车,那么SpringBoot就是自动挡的车,让我们的驾驶体验变得更好 SpringBoot具有一下几种特征…...
【Python】tkinter messagebox练习笔记
我一好友在朋友圈看到人家用代码花式秀恩爱,让我也做一个,我就用我学习半年python的功力,做了这一个东西。🙏窗口主页面(图一)为了让我这个盆友有颜面,特意做了一个问答问他帅不帅,以…...
2022年12月电子学会Python等级考试试卷(五级)答案解析
青少年软件编程(Python)等级考试试卷(五级) 分数:100 题数:38 一、单选题(共25题,共50分) 1. 下面哪个语句正确定义了元组类型数据tuple1?( ) A. t…...
计算机网络自定向下 -- 浅谈可靠性之rdt协议
可靠性数据传输原理 可靠指数据在传输过程中不错,不丢,不乱 运输层要为应用层提供一种服务:数据可以通过一条可靠的信道进行传输,在该信道中传输的数据不会受到损坏或者丢失, 实现这种服务的是可靠数据传输协议。 要实现这种服…...
制造业升级转型:制造业上市公司-智能制造词频统计数据集
发展智能制造,关乎中国制造业转型升级的成效。基于中国制造业上市公司年报,通过文本数据挖掘,提取关键词反映企业对智能制造的关切焦点,进而运用词频及共词网络分析,洞察中国智能制造的发展态势。 研究发现࿰…...
HTML 开发工具整理
一、千乐微云团队推荐的HTML开发工具Visual Studio Code 简称VS Code (第一推荐)Visual Studio Code (简称 VS Code / VSC) 是一款免费开源的现代化轻量级代码编辑器,支持几乎所有主流的开发语言的语法高亮、智能代码补全、自定义快捷键、括号…...
介绍ACE C++网络通信框架
很久以前笔者也不太熟悉ACE C网络通信框架,偶然的机会逐渐接触后,发现它的优良! 总结来看它的有点如下 非常适合后台无界面网络通信的系统编程 适合小型化核心网使用;但值得注意,如果您需要的是web领域技术栈&…...
【Mac OS】JDK 多版本切换配置
前言 由于不同的项目可能需要使用的 JDK 版本不一样,所以在系统中配置多个 JDK 版本,并且能随时切换,是一个必要的配置。 查看已安装的 JDK 版本 /usr/libexec/java_home -V框框1是执行的命令 框框2是当前系统下所有的 JDK 版本 框框3是当…...
哪里能给人做网站/河北百度推广客服电话
期权定价第九章 期权定价的有限差分方法在本章中,我们将给出几个简单的例子来说明基于偏微分方程(PDE)框架的期权定价方法。具体的方法的是利用第五章中讲述的有限差分方法来解决Black-scholes偏微分方程。在9.1节中,我们会回顾衍生品定价的数值解法以及…...
达令的网站建设/系统优化
模型一、线性模型(linear model)(一)线性回归1.一元线性回归1.1公式表示:f(x)wxib向量形式1.2线性回归模型的好处:简单、可理解1.3线性回归模型因变量是离散变量的处理方法ÿ…...
实验报告网站建设与网页制作/网络营销推广方案案例
目前有很多人会对老旧的房屋进行拆除然后重新建造,让自己能够有新的房子居住,但这不是容易完成的事情,而房屋拆除注意事项都有哪些呢?在房屋拆除之前,该了解的事情一定要了解清楚,房屋拆除应该注意问题呢。一、房屋拆…...
网站开发项目周报/西安建站推广
本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明. 需要实现的功能:采用udp下的socket编程,当按下确认键,模拟器发送文本框数据,pc机上的网络调试助手接收 环境:win7 eclipse sdk 代码: p…...
上海网站制作公司多少钱/网站推广如何引流
1.svn是什么? 代码版本管理工具,它能记住你每次的修改,仓库所有的修改记录,恢复到任何历史版本,恢复已经删除的文件。 2.svn和git比,有什么优势? 使用简单,上手快。目录级权限控制…...
架设网站是自己架设服务器还是租服务器/关键字挖掘
向上滑动阅读电脑学习是一个“绿色、实用、免费”平台,我们致力于帮助更多用户掌握电脑知识、手机技巧、互联网知识,并推荐电脑和手机等各种优质工具,发布各种实用软件及安装教程。常见问题及解决方案本公众号提供了数以万计的实用工具和教程…...