关闭

学习笔记2

295人阅读 评论(0) 收藏 举报
分类:

2013-12-02
Unix高级编程配置(ubuntu 12.04 LTS)
1.APUE2源代码下载:http://www.apuebook.com/src.tar.gz
2. 我保存到了/home/yan/下.解压缩:tar -xzvf src.tar.gz(我的普通用户为:yan)
3.cd apue.2e进入apue.2e目录,修改Make.defines.linux
   vim Make.defines.linux 修改WKDIR的值为WKDIR=/home/yan/apue.2e
4.进入apue.2e/std/linux.mk把全部的nawk改为awk.因些linux默认没有nawk,可以使用
   :%s/nawk/awk/g (在底行命令行输入,注意冒号)
5.在apue.2e下面:make    
6.sudo cp /home/yan/apue.2e/include/apue.h /usr/include
   sudo cp /home/yan/apue.2e/lib/error.c /usr/include
7. 编辑apue.h
   vim apue.h
   在最后一行 #endif  前面添加一行 #include "error.c"
   :wq 保存,退出.
OK 完成!
找个例子编译:随机编译一个fig3.2文件:
出现错误:"fig3.2: file not recognized: File format not recognized
                collect2: ld returned 1 exit status"
原因是:fig3.2文件是链接文件,链接到file/hole.c文件上,可以打开看到内容一样。
解决办法:将fig3.2换成源文件。

堆排序
1、将一个无序数组初始化为一个大根堆:
从最大非叶节点开始,调用函数:从父结点、左孩子、右孩子三者中选出最大的和父结点作交换,如果发生了交换,则从发生了交换的左孩子结点或右孩子结点递归调用该函数。最后到达根结点,完成初始化。
2、对大根堆进行排序:
因为经过初始化,最大的数肯定在根节点,所以将根结点和最后一个结点交换,然后对根结点调用上述函数,完成后可将其视为一个size-1的无序大根堆(size是堆元素的数量)即已完成1个元素的排序。重复上述2直到剩下最后一个元素即可完成堆排序。
具体算法如下:
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

using namespace std;

void HeapAdjust(int *a,int i,int size)  //堆调整,a是要调整的堆数组指针,i是要调整的结点位置,size是堆大小
{
 int lchild=2*i+1;
 int rchild=2*i+2;
 int max=i;
 if(i<=size/2-1)
 {
  if(lchild<=size-1 && a[lchild]>a[max])
  {
   max=lchild;
  }
  if(rchild<=size-1 && a[rchild]>a[max])
  {
   max=rchild;
  }
  if(max != i)  //当发生了交换时,防止交换后的子树不是大根堆,调归调用
  {
   swap(a[i],a[max]);
   HeapAdjust(a,max,size);
  }
 }
}

void BuildHeap(int *a,int size)  //初始化堆
{
 int i;
 for(i=size/2-1;i>=0;i--)   //从最大叶子结点开始进行堆调整,适用于无序二叉树初始化为无序大根堆
 {
  HeapAdjust(a,i,size);
 }
}

void HeapSort(int *a,int size)  //堆排序
{
 int i;
 BuildHeap(a,size);
 for(i=size-1;i>=0;i--)    //每次将最大元素和最后一个元素交换,然后将少一个元素的堆从根结点开始进行堆调整
 {
  swap(a[0],a[i]);
  HeapAdjust(a,0,i);
 }
}

int main(int argc,char *argv[])
{
 int a[1000];
 int size=1000;
 FILE *file=fopen("XXX","r");  //XXX表示输入文件的路径
 for(int i=0;i<size;i++)
 {
  fscanf(file,"%d",a+i);
 }
 HeapSort(a,size);
 for(int i=0;i<size;i++)
  cout<<a[i]<<" ";
 cout<<endl;
 return 0;
}
随机数的产生可以通过脚本文件产生,当然也可以自己修改用终端输入。python脚本如下所示:
#!/usr/bin/python
import random
file=open("randomnum","w")
for i in range(1000):
 file.write(repr(random.randint(1,1000))+" ")
file.close()

桥接(Bridging),是指依据OSI网络模型的链路层的地址,对网络数据包进行转发的过程。 是工作在osi的第二层的。一般的交换机,网桥就有桥接作用。就交换机来说,本身有一个端口与mac的映射表,通过这些,隔离了冲突域(collision)。 简单的说就是通过网桥可以把两个不同的物理局域网连接起来,是一种在链路层实现局域网互连的存储转发设备。网桥从一个局域网接收MAC帧,拆封、校对、校验之后 ,按另一个局域网的格式重新组装,发往它的物理层。
网桥是一种LAN连接设备,具有两个或更多的端口,用于将一个LAN(局域网)段的帧转发到另一段。过去,网桥是具有几个LAN连接器的小盒子,或者是具有几个网络接口卡的服务器。现在,网桥更可能以交换设备的形式出现,从技术上来说这种设备是多端口网桥,每一端口提供一个桥接到其他端口的独立LAN连接。
  网桥提供几个重要的功能:
  ·它允许单个LAN扩展到更大的距离上。
  ·可以在保留同样广播域的情况下用网桥将不同类型的网络链路连接起来。例如,可以使用光缆连接的网桥桥接两个相隔遥远的LAN。
  ·网桥转发帧,但是可以使用一种过滤机制阻止不必要的帧在网络上传播。
  ·它们提供了一个屏障,可以防止一个网段的电气或其他问题传播到其他网段。
  ·网桥将每个LAN与出现在其他LAN上的冲突隔离,因此,它在同一个广播域中产生独立的冲突域。
  最后一点很重要。在以太网中,当两个节点试图同时传输时会出现冲突。当向网络添加更多节点时,冲突也随之增加。网桥可用于在保留广播域的同时将一个网络分为独立的冲突域。互联网络由路由器连接的多个LAN组成,与之相比,广播域基本上是一个LAN.在广播域中,通过使用数据链路层定址,任何节点都可以向其他节点发送消息,而路由选择的网络需要互联网络寻址。
HUB所有的端口都在一个冲突域和广播域里。交换机所有端口各单独有一个冲突域,默认都在同一个广播域里,通过划分vlan可以划分不同广播域。路由器每个端口属于不同的广播域。网桥可以隔开冲突域,保留广播域。

关于UNIX文件权限
1、对于一个文件的读许可权决定了我们是否能够打开该文件进行读操作。这对应于open函数的O_RDONLY和O_RDWR标志。
2、对于一个文件的写许可权决定了我们是否能够打开该文件进行写操作。这对应于open函数的O_WRONLY和O_RDWR标志。
3、为了在open函数中对一个文件指定O_TRUNC标志,必须对该文件具有写许可权。
4、为了在一个目录中创建一个新文件,必须对该目录具有写许可权和执行许可权。
5、为了删除一个文件,必须对包含该文件的目录具有写许可权和执行许可权。对该文件本身则不需要有读、写许可权。
6、如果用6个exec函数中的任何一个执行某个文件,都必须对该文件具有执行许可权。

进程每次打开、创建或删除一个文件时,内核就进行文件存取许可权测试,而这种测试可能涉及文件的所有者(st_uid和st_gid ),进程的有效ID ( 有效用户ID和有效组ID )以及进程的添加组ID ( 若支持的话) 。两个所有者 ID是文件的性质,而有效 ID 和添加组 I D则是进程的性质。内核进行的测试是:
(1)  若进程的有效用户ID是0 (超级用户),则允许存取。这给予了超级用户对文件系统进行处理的最充分的自由。
(2)  若进程的有效用户ID等于文件的所有者ID(也就是该进程拥有此文件):
(a)  若适当的所有者存取许可权位被设置,则允许存取。
(b)  否则拒绝存取。
适当的存取许可权位指的是,若进程为读而打开该文件,则用户 -读位应为1;若进程为写而打开该文件,则用户-写位应为1;若进程将执行该文件,则用户 -执行位应为1。
(3)  若进程的有效组ID或进程的添加组ID之一等于文件的组ID:
(a)  若适当的组存取许可权位被设置,则允许存取。
(b)  否则拒绝存取。
(4)  若适当的其他用户存取许可权位被设置,则允许存取,否则拒绝存取。
按顺序执行这四步。注意,如若进程拥有此文件 (第( 2 )步),则按用户存取许可权批准或拒绝该进程对文件的存取——不查看组存取许可权。相类似,若进程并不拥有该文件。但进程属于某个适当的组,则按组存取许可权批准或拒绝该进程对文件的存取——不查看其他用户的存取许可权。
当新建一个文件时,文件是用户ID是进程的有效ID,而文件的组ID可以为进程组ID或目录组ID(根据设置)

文件权限除了r、w、x外还有s、t、i、a权限:
s:文件属主和组设置SUID和GUID,文件在被设置了s权限后在执行时将切换到相应的身份执行。(如在执行一个设置了SUID位的文件时,会切换到文件所有者的身份。GUID多用于目录,在该目录下创建新文件,其所属组ID会被设置成目录组ID)在设置s权限时文件属主、属组必须先设置相应的x权限,否则s权限并不能真正生效(chmod命令不进行必要的完整性检查,即使不设置x权限就设置s权限,chmod也不会报错,当我们ls -l时看到rwS,大写S说明s权限未生效)。Linux修改密码的passwd便是个设置了SUID的程序,普通用户无读写/etc/shadow文件的权限却可以修改自己的密码。
ls -al /usr/bin/passwd
-rwsr-xr-x 1 root root 32988 2008-12-08 17:17 /usr/bin/passwd
对应文件存取标志的s位就是通常说的SUID位,另外可以看到所有用户都有执行的这个程序权力。假设steve用户执行passwd命令的时候。Shell会fork出一个子进程,此时进程的EUID还是steve,然后exec程序/usr/bin/passwd。exec会根据/usr/bin/passwd的SUID位会把进程的EUID设成root,   此时这个进程都获得了root权限, 得到了读写/etc/shadow文件的权限, 从而steve用户可完成密码的修改。 exec退出后会恢复steve用户的EUID为steve。这样就不会使steve用户一直拥有root权限。
我们可以通过字符模式设置s权限:chmod a+s filename,也可以使用绝对模式进行设置:

设置suid:将相应的权限位之前的那一位设置为4;
设置guid:将相应的权限位之前的那一位设置为2;
两者都置位:将相应的权限位之前的那一位设置为4+2=6。
如:chmod 4764 filename   //设置SUID
t :设置粘着位,一个文件可读写的用户并一定想让他有删除此文件的权限,如果文件设置了t权限则只用属主和root有删除文件的权限,通过chmod +t filename 来设置t权限。
i:不可修改权限  例:sudo chattr +i filename 则filename文件就不可修改,无论任何人,如果需要修改需要先删除i权限,用sudo chattr -i filename就可以了。查看文件是否设置了i权限用lsattr filename。

#include <unistd.h>
int access(const char *pathname,int mode);   mode:R_OK,W_OK,X_OK,F_OK
按实际用户ID和实际用户组ID进行存取许可权测试。

#include <sys/types.h>
#include <sys/stat.h>
mode_t umask(mode_t umask);
为进程设置文件方式创建屏蔽字,并返回以前的值。

#include <sys/types.h>
#include <sys/stat.h>
chmod(const char pathname,mode_t mode);  //对路径指定文件改变权限
fchmod(int filedes,mode_t mode);  //对已打开文件改变权限

#include <sys/types.h>
#include <unistd.h>
int chown(const char pathname,uid_t owner,gid_t group);  //对路径指定文件改变所有者
int fchown(int filedes,uid_t owner,gid_t group);  //对已打开文件改变所有者
int lchown(const char pathname,uid_t owner,gid_t group);  //对符号连接本身改变所有者

#include <sys/types.h>
#include <unistd.h>
int truncate(const char pathname,off_t length);  //文件截短
int ftruncate(int filedes,off_t length);

###########################################################################
2013-12-03
文件系统的大概构成,由i表,数据块,目录块组成。
目录块由i节点号和文件名组成,i表由i节点组成,根据目录名找到i节点号,i节点号指向i节点,i节点再指向数据块或下一层的目录块。
硬连接和软连接(符号连接):
硬连接相当于一个别名,这个路径名具有与源文件相同的i节点号。
软连接相当于快捷方式,文件里存着源文件的路径直接指向源文件。
因此,删掉源文件,文件不会真正被删除,硬连接也不会失效,而软连接会失效。
硬连接不可跨文件系统,软连接可以。

#include <unistd.h>
int link(const char *existingpath,const char *newpath);
创建一个硬连接

#include <unistd.h>
int unlink(const char *pathname)
解除硬连接(即删除一个现存目录项,与remove作用相同)

#include <unistd.h>
int symlink(const char *actualpath,const char *sympath);
创建一个软连接

#include <unistd.dh>
int readlink(const char *pathname,char buf,int bufsize);
因为open跟随符号链接,所以只能用readlink来读取符号连接本身

文件时间
st_atime  文件数据的最后存取时间
st_mtime 文件数据的最后修改时间
st_ctime  i节点状态的最后更改时间
ls -l filename可以看到mtime
ls -lc filename可以看到ctime
ls -lu filename可以看到atime

#include <sys/type.h>
#include <utime.h>
int utime(const char *pathname,const struct utimbuf *times);
这里使用的结构是
struct utimbuf
{
 time_t actime;   //access time
 time_t modtime; //modification time
}
如果times是一个空指针,将存取时间和修改时间设置为当前时间。
非空,则设置为times所指向的结构中的值。

#include <sys/types.h>
#include <sys/stat.h>
int mkdir(const char *pathname,mode_t mode);
创建新目录

#include <unistd.h>
int rmdir(const char *pathname);
删除目录

与读目录有关的函数和结构:
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *pathname);
struct dirent *readdir(DIR *dp);
void rewinddir(DIR *dp);
int closedir(DIR *dp);
struct dirent
{
 ino_t d_ino;
 char d_name(NAME_MAX+1);
}

2013-12-04
关于头文件
头文件目录中总共有32个.h头文件。其中主目录下有13个,asm子目录中有4个,linux子目录中有10个,sys子目录中有5个。这些头文件各自的功能如下,具体的作用和所包含的信息请参见第14章。
<a.out.h>:a.out头文件,定义了a.out执行文件格式和一些宏。
<const.h>:常数符号头文件,目前仅定义了i节点中i_mode字段的各标志位。
<ctype.h>:字符类型头文件,定义了一些有关字符类型判断和转换的宏。
<errno.h>:错误号头文件,包含系统中各种出错号。(Linus从minix中引进的)。
<fcntl.h>:文件控制头文件,用于文件及其描述符的操作控制常数符号的定义。
<signal.h>:信号头文件,定义信号符号常量,信号结构以及信号操作函数原型。
<stdarg.h>:标准参数头文件,以宏的形式定义变量参数列表。主要说明了一个类型(va_list)和3个宏(va_start, va_arg和va_end),用于vsprintf、vprintf、vfprintf函数。
<stddef.h>:标准定义头文件,定义了NULL, offsetof(TYPE, MEMBER)。
<string.h>:字符串头文件,主要定义了一些有关字符串操作的嵌入函数。
<termios.h>:终端输入输出函数头文件,主要定义控制异步通信口的终端接口。
<time.h>:时间类型头文件,主要定义了tm结构和一些有关时间的函数原形。
<unistd.h>:Linux标准头文件,定义了各种符号常数和类型,并声明了各种函数。如,定义了__LIBRARY__,则还包括系统调用号和内嵌汇编_syscall0()等。
<utime.h>:用户时间头文件,定义了访问和修改时间结构以及utime()原型。
(1)体系结构相关头文件子目录include/asm
这些头文件主要定义了一些与CPU体系结构密切相关的数据结构、宏函数和变量。共4个文件。
<asm/io.h>:I/O头文件,以宏的嵌入汇编程序形式定义对I/O端口操作的函数。
<asm/memory.h>:内存拷贝头文件,含有memcpy()嵌入式汇编宏函数。
<asm/segment.h>:段操作头文件,定义了有关段寄存器操作的嵌入式汇编函数。
<asm/system.h>:系统头文件,定义了设置或修改描述符/中断门等的嵌入式汇编宏。
(2)Linux内核专用头文件子目录include/linux
<linux/config.h>:内核配置头文件,定义键盘语言和硬盘类型(HD_TYPE)可选项。
<linux/fdreg.h>:软驱头文件,含有软盘控制器参数的一些定义。
<linux/fs.h>:文件系统头文件,定义文件表结构(file,buffer_head,m_inode等)。
<linux/hdreg.h>:硬盘参数头文件,定义访问硬盘寄存器端口、状态码和分区表等信息。
<linux/head.h>:head头文件,定义了段描述符的简单结构,和几个选择符常量。
<linux/kernel.h>:内核头文件,含有一些内核常用函数的原形定义。
<linux/mm.h>:内存管理头文件,含有页面大小定义和一些页面释放函数原型。
<linux/sched.h>:调度程序头文件,定义了任务结构task_struct、初始任务0的数据,以及一些有关描述符参数设置和获取的嵌入式汇编函数宏语句。
<linux/sys.h>:系统调用头文件,含有72个系统调用C函数处理程序,以"sys_"开头。
<linux/tty.h>:tty头文件,定义了有关tty_io,串行通信方面的参数、常数。
(3)系统专用数据结构子目录include/sys
<sys/stat.h>:文件状态头文件,含有文件或文件系统状态结构stat{}和常量。
<sys/times.h>:定义了进程中运行时间结构tms以及times()函数原型。
<sys/types.h>:类型头文件,定义了基本的系统数据类型。
<sys/utsname.h>:系统名称结构头文件。
<sys/wait.h>:等待调用头文件,定义系统调用wait()和waitpid()及相关常数符号。

#include <unistd.h>
int chdir(const char *pathname);
int fchdir(int filedes);
改变当前进程的工作目录

#include <unistd.h>
char *getcwd(char *buf,size_t size);
获取当前工作目录

st_dev是文件所属的文件系统的主次设备号,而st_rdev是设备文件本身实际的主次设备号。

#include <unistd.h>
void sync(void);
int fsync(int filedes);
sync将所有修改过的块的缓存排入写队列,返回,不等待实际I/O操作的结束。系统精灵进程(update)一般每隔30秒就会调用一次sync函数,保证定期刷新内核的块缓存。
fsync等待I/O操作的完成。另外open的标志O_SYNC也可使每次write操作同步到文件的作用。
还有一个fdatasync函数,只更新数据,对一些非必要信息不同步(ctime等)。同上也有O_DSYNC。

流的输入输出相关函数
setbuf  setvbuf  fopen  freopen  fdopen  fclose  getc  fgetc  getchar  ferror  feof  clearerr  putc  fputc  putchar  fgets  gets  fputs  puts  fread  fwrite  ftell  fseek  fgetpos  fsetpos  printf  fprintf  sprintf  vprintf  vfprintf  vsprintf  scanf  fscanf  sscanf  fileno  tmpnam  tmpfile

设置环境变量
#include <stdlib.h>
int putenv(const char *str);
int setenv(const chr name,const char *value,int rewrite);
void unsetenv(const char name);
putenv以name=value的字符串形式将*str放入环境表中,若name已存在,则先删除原来的定义。
setenv将name设置为value,若name已存在,则根据rewrite来决定是否删除原来的定义,非0为删除。
unsetenv删除name的定义,即使不存在也不会出错。

跳转函数
#include <setjmp.h>
int setjmp(jmp_buf env);
void longjmp(jmp_buf env,int val);

对进程的资源限制可以用getrlimit和setrlimit来查询和更改
#include <sys/time.h>
#include <sys/resource.h>
int getrlimit(int source,struct rlimit *lptr);
int setrlimit(int source,const struct rlimit *lptr);
struct rlimit
{
 rlim_t rlim_cur;
 rlim_t rlim_max;
}

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:13809次
    • 积分:372
    • 等级:
    • 排名:千里之外
    • 原创:22篇
    • 转载:12篇
    • 译文:0篇
    • 评论:0条
    文章分类