Linux环境开发基础

常用服务器构建

  • 关于Ubuntu中文本编辑器vim的一个小问题:解决Ubuntu中vi命令的编辑模式下不能正常使用方向键和退格键的问题
  • 关于虚拟机中的客户机操作系统的网络适配器设置选项,应选择桥接模式,这样该虚拟机中的客户机操作系统的ip就和主机Windows系统的ip在同一网段中但不相同,从而可使虚拟机操作系统和主机操作系统之间进行通信。而选择NAT模式使虚拟机和主机操作系统共享同一个ip。

ftp

服务器搭建步骤:

  • 实名用户登录ftp的方式:
1. 安装   sudo apt-get install vsftpd //ubuntu中有很多种ftp服务器,此处选择安装vsftpd服务器

2. 配置   sudo vi /etc/vsftpd.conf
    尽量不要手写内容到文件中。通过打开、关闭注释的方式调整该文件。

3. 启动 (重启——如果修改过配置必须重启)
    sudo service vsftpd restart

4. 客户端发起链接
    ftp 127.0.0.1(自己充当服务器、自己充当客户端)
    ftp 192.168.36.xxx(对方IP)

5. 数据传递(上传、下载)
    下载:get  非目录
    上传:put  非目录

6. 关闭连接
    quit/exit/bye
  • 上述第四步客户端发起链接时需要输入服务器的用户名和登录密码,连上服务器之后,客户端可以自由地在服务器的文件系统中自由切换访问。这种服务器贡献密码并开放权限的做法不值得提倡。因此引出以下匿名登录ftp服务器的方式。
  • 允许上传、下载,但仅开放指定服务器目录,并且不贡献服务器的登录密码。系统默认指定了一个服务器目录给匿名登录用户使用,在/etc/passwd中可查到默认ftp服务器的开放目录。
  • 匿名用户登录ftp的方式:
1. 创建匿名用户登录位置。
    cat /etc/passwd | grep ftp  查找本机默认指定 匿名用户登录位置。——/srv/ftp

2. sudo mkdir /srv/ftp/incoming 
   //此处之所以要在默认登录文件夹位置里再创建一个子文件夹,
   //是因为默认位置文件夹的权限限制用户ftp对该目录进行写操作,后果是不能使用put上传文件到该服务器目录
   //默认文件夹的权限见下图
   //虽然简单粗暴的方法是修改这个默认登录文件夹的权限对同组用户开放写权限,
   //不过更好的方式是在该目录下新建一个为用户ftp所有的子文件夹,
   //以后每次登录上ftp服务器后都对应地进入默认登录文件夹下的指定子文件夹进行上传和下载操作。
   //这样,当多个用户连接上同一个ftp服务器时各自对应操作不同的文件夹,更有条理。子文件夹权限设置见以下第三步。

3. sudo chown ftp:nogroup /srv/ftp/incoming ——所有者:ftp  所属组:nogroup
   //此处是修改incoming文件夹的权限为用户ftp所有,见下图

4. 修改配置文件,给匿名用户开放各种权限。/etc/vasftpd.conf

5. sudo service vsftpd restart

6. ps aux | grep ftp   ——查询结果应为2+ 才表示启动成功

7. ftp 127.0.0.1  ——用户名:anonymous   密码:回车

8. 默认匿名用户登录上以后在/srv/ftp(默认)

9. cd  incoming (注意目录权限)

10  put 上传  get 下载。

系统默认的服务器登录文件夹的权限
其中,ftp用户拥有第二组(同一组内)权限。
新建子文件夹的权限
其中,ftp用户拥有第一组(所有者)权限。
- 但是。ftp服务器只能上传和下载文件而不能操作不能文件夹,因此引出 lftp 服务器。

lftp

  • lftp服务器搭建和使用步骤:
lftp使用:

1. sudo apt-get install lftp  安装lftp客户端

2. 配置vsftpd.conf(与ftp共享同一个配置文件)

3. restart

4. 登录lftp 127.1

5. login itcat/anonymous    (匿名用户可省略该步)

6. mirror -R 上传目录

7. mirror  目录下载

8. bye

另外,lftp 下的中文默认使用UTF-8,可正确显示中文;而ftp 下的中文为乱码。因此,推荐使用 lftp。

  • 上传位置:ftp或lftp登录后,cd到哪个目录执行put/mirror -R 就上传至哪个目录。
  • 下载位置:默认情况从哪个目录执行了ftp 127.0.0.1 就get到哪个目录,
    可以使用lcd 改变本地机的工作目录位置。
    lcd ..可以修改至上级目录
    !ls 列出本地机列表项;
    !pwd 查看本地机工作目录位置。

nfs

nfs使用流程:

1.安装:sudo apt-get install nfs-kernel-server

2.创建一个欲共享出去的目录 如:/home/itcast/itcast

3.打开配置文件:sudo vi /etc/exports 

4.写入共享目录的绝对路径,及对应权限。如:

    /home/itcast/itcast *(ro,sync,no_root_squash)
5.重启nfs  

    sudo /etc/init.d/nfs-kernel-server restart

    -------------------------

6.客户端访问共享目录:

    sudo mount 192.168.43.75:/home/itcast/itcast/ /mnt

7. cd 到本机的/mnt 目录中就可以使用cp命令得到目录中的所有文件。


【常见错误】:1. 虚拟机下出现“不能mount实体”错误时,需在mount之前使用

         install nfs-common 即可解决。

          2. 出现“超级坏块儿”错误无法挂载,多是因为没有安装nfs-kernel-server导致。

ssh

scp

  • 其实不是一种服务器,而是一条远程拷贝命令。

对比语法格式:

nfs:sudo mount 192.168.43.75:/home/itcast/itcast/ /mnt

ssh: ssh itcast@192.168.43.75   ——>yes   密码

scp -r itcast@192.168.43.75:/home/itcast/aa ../
  • nfs 和 ssh 服务器的使用需要知道对方主机的登录密码。而scp命令不需要,而且也不需要搭建服务器即可传数据。

telnet

  • 明文传输二进制数据流,不安全,不推荐使用。

开发工具

gcc(编译器)

Linux环境开发基础_第1张图片
在这四个过程中,编译过程耗时最长,因为编译要逐条检查语法错误,然后和标准语法比对。
若程序包括自己写的头文件但该头文件不在程序所在的同一个文件夹下,就使用 -I 参数后接这个自定义头文件所在的文件夹。
objdump -dS后接目标文件(.o)或可执行文件(.out)可反汇编二进制文件为汇编程序。
- 可执行程序(.out)运行起来后被加载到内存中,那么可执行程序在内存中的布局是怎么的呢?
Linux环境开发基础_第2张图片
上图是32位内存空间的布局:
最上面为内核区(kernel),下面为用户区(user)。用户无权访问内核区。对于用户区,从低地址开始向上:
最下面为ELF header,记录ELF文件的属性信息;
上面为.text区,即代码段,存放代码(只读);
上面为ordata区,存放常量(只读);
上面为.data区,即数据段,存放全局变量;
上面为.bss区,存放未初始化的全局变量和静态局部变量;
上面为堆区,生长方向为从低地址到高地址;
用户区最上面为栈区,生长方向为从高地址向低地址。
当栈和堆生长到彼此接触时,则表明发生了内存溢出!
栈中存放的是一个个栈帧,即函数调用的存储子空间,栈帧中具体存放的是被调用函数的局部变量和临时值,临时值保存的是被调函数的返回地址,被调函数的形参(若有)和其内部的局部变量等价。


静态库

  • 函数库:一组功能相近或者操作同一个数据结构的函数的结合。发布形式分为源码形式(开源)和二进制文件形式,后者更常见。
  • 二进制库的优点是免去编译过程,而且可隐藏内部实现细节。分静态库和动态库(共享库)。
  • 机制:复制静态库作为程序代码段的一部分。
  • 优点:将函数库中的函数本地化。寻址方便,速度快。(库函数调用效率 == 自定义函数使用效率,达到直接跳转)
  • 缺点:消耗系统资源较大。每个进程使用静态库都要复制一份。无端浪费内存
  • 使用场景:多应用于核心程序,保证时效性,可以忽视空间。
  • 静态库发布形式为二进制文件(.o),并且静态库的命名规范为:lib开头,.a结尾
  • 制作静态库:
1. gcc add.c sub.c mul.c -c         ——>得到*.o

2. ar rs libmymath.a add.o sub.o mul.o  ——>得到静态库

    ar工具不包含在gcc中

    r更新、c创建、s建立索引

    file libmymath.a   ——>查看库信息

3. gcc main.c -L ./ -l mymath -I ./ -o app   ——>使用静态库

    使用:L:指定静态库所在目录位置;l:指定静态库名字(此处为去掉lib前缀和.a后缀后的名字) I:指定头文件所在目录位置
  • 比如有三个子文件add.c、sub.c、mul.c,和main.c联合编译生成一个可执行程序:
    gcc add.c sub.c mul.c main.c -o app
    而把前三个子文件制作成一个静态库以后就可以借助这个静态库和main.c一起联合编译了。

动态库(共享库)

  • 机制:共享代码(不共享数据,比如在动态库文件中存在变量和宏的时候)
  • 优点:节省内存(共享)、易于更新(动态链接)
    多个程序共享同一份动态库;当可执行文件a.out开始运行时才加载动态库。
    注意:动态库加载到内存中的位置是在栈和堆之间的一块内存区域中。
  • 缺点:相较于静态库函数调用速度略慢(延迟绑定机制)
  • 使用场景:
    (1)对程序执行速度要求不是很强烈,而相对于系统资源有一定要求的场景
    (2)对于更新比较频繁的程序
    当可执行文件在运行时,它所加载的动态库发生修改时:
    1)停止运行程序
    2)使用新库覆盖旧库(保证新旧库名称一致,接口一致) “接口”
    3)重新启动程序。
  • 注意:
    (1)动态库是否加载到内存,取决于程序是否运行
    (2)动态库每次加载到内存的位置不固定(地址是相对地址)—-动态链接器(工作在程序运行期间,区别于链接器,它工作在程序编译期间)
  • 制作动态库:
1. gcc -fPIC add.c mul.c sub.c -c (-fPIC:生成“与位置无关”的目标文件*.o2. gcc -shared -o libmymath.so add.o mul.o sub.o

3. gcc main.c -L库路径 -l库名 -I头文件名  -o app

4. ./app --> 出错     

   原因:动态连接器 ld-linux.so.2 搜寻动态库的路径未指定,

     执行ldd app发现动态链接器找不到 libmymath 库。

   指定方法(推荐第34种方法):

    1). 环境变量法:export LD_LIBRARY_PATH=./ 将当前目录加入环境变量,但是终端退出了就无效了。

    2). 配置文件法:将上条写入家目录下.bashrc文件中   (永久生效,设置到~/.bashrc3). 拷贝法:直接将libmymath.so文件拷贝到/usr/lib/目录下。
       (受libc库的启发,因为动态链接器在搜索标准C库时会去这个目录下找,而且也说明标准C库也是一个动态库)

    4). 缓存文件法:将libmymath.so所在绝对路径加入到/etc/ld.so.conf文件(保存动态链接器默认搜索动态库的路径),

       使用sudo ldconfig -v 动态更新/etc/ld.so.cache文件(2进制文件,
       它是实际真正影响动态库加载路径的文件,但由于是二进制文件,不方便直接修改它,因此通过修改上面这个.conf文件来影响它。)
动态库的规范使用方法:
 5. 指定动态库的soname
 gcc -shared -Wl,-soname,libmymath.so.1 -o libmymath.so.1.10 add.o mul.o sub.o
 soname的作用是隐藏库的实现细节,不让用户知晓版本调整细节信息。
 6.创建动态库的LinkerName
 ln -s libmymath.so.1.10 libmymath.so
 也即创建动态库的软链接,在使用这个动态库联合编译时就是用的是它的软链接名。
  • 注意:
    1)动态库是否加载到内存取决于程序是否运行;
    2)动态库每次加载到内存中的位置不固定。
  • 动、静态库共存时:
    1)编译器默认使用.so的动态库,找不到才使用静态库。
    2)-static可以直接指定使用静态库
    3)注意比较加了static和没有加static的可执行文件大小,及内部printf的地址。显然是加了static(使用静态库)的可执行文件更大。

gdb(调试工具)

  • 使用场景:程序编译无误,但是有逻辑错误,即程序无语法错误但运行结果不正确。
  • 使用参数:
    1)首先在前一步gcc编译时要加-g 参数,这样得到的可执行程序文件包含调试信息,才能把生成的可执行程序xxx用于gdb调试 —> gdb xxx
    2)list或简写为l : 列出程序源码
    3)b 行号:设置断点所在行号
    4)info b : 查看断点信息
    5)disable/enable 断点号 : 设置断点非使能/使能
    6)delete 断点号: 删除断点
    7)b 行号 if i=5 : 设置条件断点,只有i=5时断点生效
    8)run:全速执行程序,若程序无错误,会很快结束,但若有错,则会停在出错处。比如,编译时出现段错误(segmentation fault),执行run命令,会很方便地知道出现段错误的地方。
    9)start:从首行执行,单步调试
    10)p 变量名——查看变量值
    11)display——跟踪变量
    12)undisplay——取消跟踪
    13)ptype 变量名——查看变量类型
    14)bt : 查看当前程序函数栈帧使用基本情况
    函数的栈帧保存局部变量和临时值,形参与局部变量等价。
    15)info locals: 查看当前栈帧上变量的存储值
    16)frame 栈帧编号: 查看对应栈帧中变量的值
    17)s——step,进入到调用子函数内部继续跟踪
    18)n——next,跳过调用子函数继续调试
    19)finish : 终止当前函数
    20)continue 结束当前断点调试,跳到下一个断点(若有)
    21)quit:退出gdb调试
  • 总结:
命令 简写 作用
help h 按模块列出命令类
help class 查看某一类型的具体命令
list l 查看代码,可跟行号和函数名
quit q 退出gdb
run r 全速运行程序
start 单步执行,运行程序,停在第一行执行语句
next n 逐过程执行
step s 逐语句执行,遇到函数,跳到函数内执行
backtrace bt 查看函数的调用的栈帧和层级关系
info i 查看GDB内部局部变量的数值,info breakpoints
frame f 切换函数的栈帧
finish 结束当前函数,返回到函数调用点
set 设置变量的值set var n=100
run argv[1] argv[2] 调试时命令行传参
print p 打印变量和地址
break b 设置断点,可根据行号和函数名
delete d 删除断点d breakpoints NUM
display 设置观察变量
undisplay 取消观察变量
continue c 继续全速运行剩下的代码
enable breakpoints 启用断点
disable breakpoints 禁用断点
x 查看内存x /20xw 显示20个单元,16进制,4字节每单元
watch 被设置观察点的变量发生修改时,打印显示
i watch 显示观察点
core文件 ulimit -c 1024 开启core文件,调试时gdb a.out core

makefile

  • 提高程序编译效率的脚本文件。其作用是将程序编译期间使用到的命令组织成一个脚本文件,方便同一管理和维护,降低程序重复编译出错概率。作用是项目编译管理、提高编译效率、降低编译出错概率。这个文件必须命名为makefileMakefile。里面都是一组一组的规则:目标、依赖条件、命令。
    vim编辑Makefile出现missing separator的解决方法
  • makefile文件若采用硬编码方式编写,则灵活性较差,应采用软编码方式,即使用变量和函数。其中,变量分为手动变量和自动变量。
  • 手动变量
    在Makefile中使用变量有点类似于C语言中的宏定义,使用该变量相当于内容替换,使用变量可以使Makefile易于维护,修改内容变得简单。
//变量定义和使用:
//1、变量定义直接用'='
//2、使用变量值用$(变量名)
foo = abc
bar = $(foo) //索引变量值
//手动定义了两个变量:foo、bar,其中bar的值是foo变量值的引用。
  • 自动变量:
//**自动变量**:
$@:在命令中表示规则中的目标
$<:在命令中表示规则中的第一个条件
$^:在命令中表示规则中的所有条件,组成一个列表,以空格隔开,如果这个列表中有重复的项则消除重复项。

通常我们在Makefile中会定义一些变量,方便Makefile的修改维护。

  • 模式规则:
    至少在规则的目标定义中要包含’%‘,’%‘表示一个或多个,在依赖条件中同样可以使用’%‘,依赖条件中的’%’的取值,取决于其目标,比如:
//以下列形式代替多组相同形式的规则
%.o:%.c
%:%.c
$(target):%:%.c //静态模式规则,针对某个集合来使用该组模式,比如:
$(obj):%.o:%.c
    $(CC) -c $< -o $@
//上句静态模式规则的含义是,把变量obj中的每个成员都用这条模式规则来生成
$(CC) –c $(CFLAGS) $(CPPFLAGS) $< -o $@
//其中,“$@”表示依次取出目标值,$<表示依次取出依赖条件。
//注意:只有写成模式规则的时候,$<才表示了所有依赖条件的依次取值
//否则只是取依赖条件中的第一个。
  • makefile函数
src = $(wildcard *.c) //找到当前目录下所有后缀为.c的文件,赋值给src

obj = $(patsubst %.c,%.o, $(src)) //把src变量里所有后缀为.c的文件替换成.o
  • clean:没有依赖,只有命令
    1) 用途:清除编译生成的中间.o文件和最终目标文件
    2) make clean 如果当前目录下有同名clean文件,则不执行clean对应的命令
    3) 伪目标声明:.PHONY:clean
    所谓伪目标,是makefile中无论其依赖条件满足或不满足,该规则都会执行
    4) clean命令中的特殊符号
    – “-”此条命令出错,make也会继续执行后续的命令。如:“-rm main.o”
    – “@”不显示命令本身,只显示结果。如:“@echo”clean done“”

  • 其它
    – ALL:指定最终要生成的目标
    – make -n:只打印要执行的命令,不会真正执行命令
    – make -f:执行一个名称为非makefile/Makefile的文件
    – make 默认执行第一个出现的目标,可通过make dest指定要执行的目标
    – distclean目标
    – install目标
    – make -C 指定目录进入指定目录,调用里面的Makefile

  • 常见C项目结构:
    Linux环境开发基础_第3张图片

你可能感兴趣的:(Linux)