分类: LINUX
2008-12-23 19:06:08
termios结构体内容:
成员 描述
-------------------------------------------
c_cflag 控制模式标志
c_lflag 本地模式标志
c_iflag 输入模式标志
c_oflag 输出模式标志
c_line line discipline
c_cc[NCCS] 控制字符
c_ispeed 输入波特率
c_ospeed 输出波特率
在termios结构中的四个标志控制了输入输出的四个不同部份。输入模式标志c_iflag决定如何解释和处理接收的字符。输出模式标志 c_oflag决定如何解释和处理发送到tty设备的字符。控制模式标志决定设备的一系列协议特征,这一标志只对物理设备有效。本地模式标志 c_lflag决定字符在输出前如何收集和处理。
在串口传输中,用波特率来表示传输的速度,1波特表示在1秒钟内可以传输1个码元。波特率设置可以使用 cfsetispeed(&new_termios,B19200)和 cfsetospeed(&new_termios,B19200)这两个函数来完成,默认的波特率为9600baud。 cfsetispeed()函数用来设置输入的波特率,cfsetospeed()函数用来设置输出的波特率。B19200是termios.h头文件里 定义的一个宏,表示19200的波特率。
CLOCAL和CREAD是c_cflag成员中与速率相关的标志,在串口编程中,这两个标志一定要有效,以确保程序在突发的作业控制或挂起时,不会成为端口的占有都,同时串口的接收驱动会自动读入数据。设置方法如下:
termios_new.c_cflag |= CLOCAL; //保证程序不会成为端的占有者
termios_new.c_cflag |= CREAD; //使端口能读取输入的数据
设置串口属性不能直接赋值,要通过对termios不同成员进行"与"和"或"操作来实现。在termios.h文件,定义了各种常量,如上面介绍 的CLOCAL,CREAD。这些常量的值是掩码,通过把这些常量与termios结构成员进行逻辑操作就可实现串口属性的设置。在编程时用"|="来启 用属性,用"&=~"来取消属性。
BRKINT和IGNBRK
如果设置了IGNBRK,中断条件被忽略。如果没有设置IGNBRK而设置了BRKINT,中断条件清空输入输出队列中所有的数据并且向tty的前 台进程组中所有进程发送一个SIGINT信号。如果这两个都没有设置,中断条件会被看作一个0字符。这时,如果设置了PARMRK,当检测到一个帧误差时 将会向应用程序发送三个字节'\377''\0''\0',而不是只发送一个'\0'。
PARMRK和IGNPAR
如果设定了IGNPAR,则忽略接收到的数据的奇偶检验错误或帧错误(除了前面提到的中断条件)。如果没有设置IGNPAR而设置了PARMRK, 当接收到的字节存在奇偶检验错误或帧错误的时候。将向应用程序发送一个三字节的'\377''\0''\n'错误报告。其中n表示所接收到的字节。如果两 者都没有设置,除了接收到的字节存在奇偶检验错误或帧误差之外的中止条件都会向应用程序发送一个单字节('\0')的报告。
INPCK
如果设置,则进行奇偶校验。如果不进行奇偶检验,PARMRK和IGNPAR将对存在的奇偶校验错误不产生任何的影响。
ISTRIP
如果设置,所接收到的所有字节的高位将会被去除,保证它们是一个7位的字符。
INLCR
如果设置,所接收到的换行字符('\n')将会被转换成回车符('\r')。
IGNCR
如果设置,则会忽略所有接收的回车符('\r')。
ICRNL
如果设置,但IGNCR没有设置,接收到的回车符向应用程序发送时会变换成换行符。
IUCLC
如果IUCLC和IEXTEN都设置,接收到的所有大写字母发送给应程序时都被转换成小写字母。POSIX中没有定义该标记。
IXOFF
如果设置,为避免tty设备的输入缓冲区溢出,tty设备可以向终端发送停止符^S和开始符^Q,要求终端停止或重新开始向计算机发送数据。通过停止符和开始符来控制数据流的方式叫软件流控制,软件流控制方式较少用,我们主要还是用硬件流控制方式。硬件流控制在c_cflag标志中设置。
IXON
如果设置,接收到^S后会停止向这个tty设备输出,接收到^Q后会恢复输出。
IXANY
如果设置,则接到任何字符都会重新开始输出,而不仅仅是^Q字符。
IMAXBEL
如果设置,当输入缓冲区空间满时,再接收到的任何字符就会发出警报符'\a'。POSIX中没有定义该标记。
OPOST是POSIX定义的唯一一个标志,只有设置了该标志后,其它非POSIX的输出标记才会生效。
OPOST
开启该标记,后面的输出标记才会生效。否则,不会对输出数据进行处理。
OLCUC
如果设置,大写字母被转换成小写字母输出。
ONLCR
如果设置,在发送换行符('\n')前先发送回车符('\r')。
ONOCR
如果设置,当current column为0时,回车符不会被发送也不会被处理。
OCRNL
如果设置,回车符会被转换成换行符。另外,如果设置了ONLRET,则current column会被设为0.
ONLRET
如果设置,当一个换行符或回车符被发送的时候,current column会被设置为0。
OXTABS
如果设置,制表符会被转换成空格符。
CLOCAL
如果设置,modem的控制线将会被忽略。如果没有设置,则open()函数会阻塞直到载波检测线宣告modem处于摘机状态为止。
CREAD
只有设置了才能接收字符,该标记是一定要设置的。
CSIZE
设置传输字符的位数。CS5表示每个字符5位,CS6表示每个字符6位,CS7表示每个字符7位,CS8表示每个字符8位。
CSTOPB
设置停止位的位数,如果设置,则会在每帧后产生两个停止位,如果没有设置,则产生一个停止位。一般都是使用一位停止位。需要两位停止位的设备已过时了。
HUPCL
如果设置,当设备最后打开的文件描述符关闭时,串口上的DTR和RTS线会减弱信号,通知Modem挂断。也就是说,当一个用户通过Modem拔号登录系统,然后注销,这时Modem会自动挂断。
PARENB和PARODD
如果设置PARENB,会产生一个奇偶检验位。如果没有设置PARODD,则产生偶校验位,如果设置了PARODD,则产生奇校验位。如果没有设置PARENB,则PARODD的设置会被忽略。
CRTSCTS
使用硬件流控制。在高速(19200bps或更高)传输时,使用软件流控制会使效率降低,这个时候必须使用硬件流控制。
只有在本地模式标志c_lflag中设置了IEXITEN时,POSIX没有定义的控制字符才能在Linux中使用。每个控制字符都对应一个按键组合(^C、^H等),但VMIN和VTIME这两个控制字符除外,它们不对应控制符。这两个控制字符只在原始模式下才有效。
c_cc[VINTR]
默认对应的控制符是^C,作用是清空输入和输出队列的数据并且向tty设备的前台进程组中的每一个程序发送一个SIGINT信号,对SIGINT信号没有定义处理程序的进程会马上退出。
c_cc[VQUIT]
默认对应的控制符是^\,作用是清空输入和输出队列的数据并向tty设备的前台进程组中的每一个程序发送一个SIGQUIT信号,对SIGQUIT信号没有定义处理程序的进程会马上退出。
c_cc[verase]
默认对应的控制符是^H或^?,作用是在标准模式下,删除本行前一个字符,该字符在原始模式下没有作用。
c_cc[VKILL]
默认对应的控制符是^U,在标准模式下,删除整行字符,该字符在原始模式下没有作用。
c_cc[VEOF]
默认对应的控制符是^D,在标准模式下,使用read()返回0,标志一个文件结束。
c_cc[VSTOP]
默认对应的控制字符是^S,作用是使用tty设备暂停输出直到接收到VSTART控制字符。或者,如果设备了IXANY,则等收到任何字符就开始输出。
c_cc[VSTART]
默认对应的控制字符是^Q,作用是重新开始被暂停的tty设备的输出。
c_cc[VSUSP]
默认对应的控制字符是^Z,使当前的前台进程接收到一个SIGTSTP信号。
c_cc[VEOL]和c_cc[VEOL2]
在标准模式下,这两个下标在行的末尾加上一个换行符('\n'),标志一个行的结束,从而使用缓冲区中的数据被发送,并开始新的一行。POSIX中没有定义VEOL2。
c_cc[VREPRINT]
默认对应的控制符是^R,在标准模式下,如果设置了本地模式标志ECHO,使用VERPRINT对应的控制符和换行符在本地显示,并且重新打印当前缓冲区中的字符。POSIX中没有定义VERPRINT。
c_cc[VWERASE]
默认对应的控制字符是^W,在标准模式下,删除缓冲区末端的所有空格符,然后删除与之相邻的非空格符,从而起到在一行中删除前一个单词的效果。POSIX中没有定义VWERASE。
c_cc[VLNEXT]
默认对应的控制符是^V,作用是让下一个字符原封不动地进入缓冲区。如果要让^V字符进入缓冲区,需要按两下^V。POSIX中没有定义VLNEXT。
要禁用某个控制字符,只需把它设置为_POSIX_VDISABLE即可。但该常量只在Linux中有效,所以如果程序要考虑移植性的问题,请不要使用该常量。
ICANON
如果设置,则启动标准模式,如果没有设置,则启动原始模式。
ECHO
如果设置,则启动本地回显。如果没有设置,则除了ECHONL之外,其他以ECHO开头的标记都会失效。
ECHOCTL
如果设置,则以^C的形式打印控制字符,如:按Ctrl+C显示^C,按Ctrl+?显示^?。
ECHOE
如果在标准模式下设定了ECHOE标志,则当收到一个ERASE控制符时将删除前一个显示字符。
ECHOK和ECHOKE
在标准模式下,当接收到一个KILL控制符,则在缓冲区中删除当前行。如果ECHOK、ECHOKE和ECHOE都没有设置,则用ECHOCTL表示的KILL字符(^U)将会在输出终端上显示,表示当前行已经被删除。
如果已经设置了ECHOE和ECHOK,但没有设置ECHOKE,将会在输出终端显示ECHOCTL表示的KILL字符,紧接着是换行,如果设置了OPOST,将会通过OPOST处理程序进行适当的处理。
如果ECHOK、ECHOKE和ECHOE都有设置,则会删除当前行。
在POSIX中没有定义ECHOKE标记,在没有定义ECHOKE标记的系统中,设置ECHOK则表示同时设置了ECHOKE标志。
ECHONL
如果在标准模式下设置了该标志,即使没有设置ECHO标志,换行符还是会被显示出来。
ECHOPRT
如果设置,则字符会被简单地打印出来,包括各种控制字符。在POSIX中没有定义该标志。
ISIG
如果设置,与INTR、QUIT和SUSP相对应的信号SIGINT、SIGQUIT和SIGTSTP会发送到tty设备的前台进程组中的所有进程。
NOFLSH
一般情况下,当接收到INTR或QUIT控制符的时候会清空输入输出队列,当接收到SUSP控制符时会清空输入队列。但是如果设置了NOFLUSH标志,则所有队列都不会被清空。
TOSTOP
如果设置,则当一个非前台进程组的进程试图向它的控制终端写入数据时,信号SIGTTOU会被被发送到这个进程所在的进程组。默认情况下,这个信号会使进程停止,就像收到SUSP控制符一样。
IEXIEN
默认已设置,我们不应修改它。在Linux中IUCLC和几个与删除字符相关的标记都要求在设置了IEXIEN才能正常工作。
设置流控制
termios_new.c_cflag &= ~CRTSCTS; //不使用流控制
termios_new.c_cflag |= CRTSCTS; //使用硬件流控制
termios_new.c_iflag |= IXON|IXOFF|IXANY; //使用软件流控制
屏蔽字符大小位
termios_new.c_cflag &= ~CSIZE;
设置数据位大小
termios_new.c_cflag |= CS8; //使用8位数据位
termios_new.c_cflag |= CS7; //使用7位数据位
termios_new.c_cflag |= CS6; //使用6位数据位
termios_new.c_cflag |= CS5; //使用5位数据位
设置奇偶校验方式
termios_new.c_cflag &= ~PARENB; //无奇偶校验
termios_new.c_cflag |= PARENB; //奇校验
termios_new.c_cflag &= ~PARODD;
termios_new.c_cflag |= PARENB; //偶校验
termios_new.c_cflag &= ~PARODD;
停止位
termios_new.c_cflag |= CSTOPB; //2位停止位
termios_new.c_cflag &= ~CSTOPB; //1位停止位
输出模式
termios_new.c_cflag &= ~OPOST; //原始数据(RAW)输出
控制字符
termios_new.c_cc[VMIN] = 1; //读取字符的最小数量
termios_new.c_cc[VTIME] = 1; //读取第一个字符的等待时间
关闭终端回显,键盘输入的字符不会在终端窗口显示。
#include
#include
#include
#include
int main(void)
{
struct termios ts,ots;
char passbuf[1024];
tcgetattr(STDIN_FILENO,&ts); /* STDIN_FILENO的值是1,表示标准输入的文件描述符 */
ots = ts;
ts.c_lflag &= ~ECHO; /* 关闭回终端回显功能*/
ts.c_lflag |= ECHONL;
tcsetattr(STDIN_FILENO,TCSAFLUSH,&ts); /* 应用新终端设置 */
fgets(passbuf,1024,stdin); /* 输入字符不会在终端显示 */
printf("you input character = %s\n",passbuf);
tcsetattr(STDIN_FILENO,TCSANOW,&ots); /* 恢复旧的终端设备 */
}
Table of Contents
Linux内核以稳定和安全著称,但随着Linux使用范围的不断扩展,各种漏洞也慢慢被内核开发人员或黑客发现。这里介绍有关Linux内核和基于Linux的开源软件的安全问题。
权限提升类
拒绝服务类
溢出类
IP地址欺骗类
Table of Contents
在实际解决问题的时候,各种数据都不是孤立的,数据之间总是存在关系,这种数据之间的关系叫做数据结构。我们可以把数据结构的形式归并为四种:
集合:数据之间没有对应关系,但同属于一个集合。如汽车是一个集合,编程语言也是一个集合。
线性结构:各数据有一一对应的关系,有前驱也有后续。
树形结构:各数据间存在一对多的关系,有一个前驱但有多个后续。
图:各数据间有多对多的关系,对前驱和后续没有限制。
数据类型是一个值的集合和定义在这个值集上的一组操作的总称。
数据类型可分两类,一类是每个对象仅由单值组成,称为原子类型,如整型、字符型等。另一类是由某种结构组成的类型,叫结构类型,如数组、字符串等。
抽象数据结构(Abstract Data Type,ADT)是一种数据类型及在这个类型上定义的一组合法的操作。
算法(Algorithm)是一个有穷规则(或语句、指令)的有序集合。通俗地说,就是计算机解决问题的过程。算法应具备以下几个重要的特性:
输入:一个算法有零个或多个输入。
输出:一个算法至少有一个输出,这种输出是同输入有着某些特定关系的量。没有输出的算法是没有意义的。
有穷性:一个算法必须总是在执行有穷步之后结束,且每一步都在有穷时间内完成。
确定性:算法中每条指令的含义都必须明确,无二义性。对相同的输入,必须有相同的结果。
可行性:算法中的每条指令的执行时间都是有限的。
描述算法的工具:自然语言、流程图、形式化语言和程序设计语言。
由瑞士科学家Niklaus Wirthrn提出的计算机界公认的公式:算法 + 数据结构 = 程序
算法设计的要求:正确、可读、健壮、快速、节省存储空间。
线性结构中的数据元素之间是一种线性关系,数据元素一个接一个地排列。如排除的队列、表格中一行行的记录等。数据元素可以包含多个数据项(字段),包含多个数据项的数据元素叫做记录。由大量记录组成的线性表又称为文件。
线性表的数学表示模型:a0,a1,a2,...a(n-1)。
顺序连续存放的线性表是最简单的,称为顺序存储结构线性表。它在内存开辟一片连续的存储空间,让线性表的第一个元素存放在内存空间的第一个位置,第 二个元素存放在第二个位置,其它元素以此类推。数据元素间的前驱和后继关系表现在存放位置的前后关系上。顺序存储结构线性表算法在插入或删除操作时的效率 不高。平均起来,每插入或删除一个元素需要移动一半的元素,最坏的情况更要移动全部的元素。另外,顺序表不利于存储空间的分配。在经常需要进入插入或删除 操作的线性表中,使用顺序存储结构线性表是不合适的。所以我们有了链式存储结构线性表。
链式存储结构线性表由结点组成,每个节点由一个数据元素和一个指向下个结点的指针组成。每个结点中如果只有一个指向后续指针的链表,叫单链表。由于链表通过指针指向下一个结点,所以数据元素可以分散存储。
单链表的建立是一种动态内在管理操作,表中的每个节点占用的存储空间无需预先指定,而是在运行时动态申请。
单链表一旦创建就可对链表进行操作。
查找值为x的节点,并返回该节点地址。算法分析:从单链表的第一个节点开始,判断当前节点的数据域的值是否为x,若是,则返回该节点的指针域,否则,依据指针域内的指针查找下一节点,直至表结束。若找不到,则返回空。
查找第i个节点,返回期指针。算法分析:从单链表的第一个节点开始,依次判断当前节点是否为第i个节点,若是则返回其指针,否则,依据指针域内的指针查找下一节点,直至表结束。若找不到,则返回空。
Table of Contents
EthernetII帧的结构(DMAC+SMAC+Type+Data+CRC),EthernetII帧的大小是有限制的,最小不能小于64字节,最大不能超过1518字节,否则帧会被丢弃。一个EthernetII帧包括的内容有:
DMAC,目的MAC地址,占48个bit,共6个字节。
SMAC,源MAC地址,占48个bit,共6个字节。
Type,帧类型,如ip,arp等。占16个bit,共2个字节。
Data,帧数据,容量是变化的,但最大不能越过1500个字节,最小不能小于46个字节。
CRC,校验码,占32个bit,共4个字节。
IP包结构:
下面我们开发一个模拟Echo服务功能的tcp程序。通过这个简单的程序我们可以学习tcp/ip网络编程的基础结构。
tcpserver.c是服务端程序,运行后会监听一个端口。
debian:~/c/kernelmodule# cat tcpserver.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc,char *argv[]){
int iswork,data,fd1,fd2;
pid_t pidchild;
socklen_t clientlen;
struct sockaddr_in clientaddr;
struct sockaddr_in serveraddr;
char buffer[1000];
if(argc != 2){
printf("Usage: tcpserver [port number]\n");
exit(1);
}
if((fd1 = socket(AF_INET,SOCK_STREAM,0))<0){
printf("socket error!\n");
exit(1);
}
memset(&serveraddr,0,sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(atoi(argv[1]));
if(bind(fd1,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0){
printf("bind error!\n");
exit(1);
}
if(listen(fd1,3)<0){
printf("listen error!\n");
exit(1);
}
iswork = 1;
while(iswork){
clientlen = sizeof(clientaddr);
if((fd2 = accept(fd1,(struct sockaddr *)&clientaddr,&clientlen))<0){
printf("accept error!\n");
exit(1);
}
if((pidchild = fork()) == -1){
printf("fork error!\n");
exit(1);
}
if(pidchild == 0){
if(close(fd1) == -1){
printf("close error!\n");
exit(1);
}
printf("Connect from %s\n",inet_ntoa(clientaddr.sin_addr));
while(1){
memset(buffer,0,1000);
if(data = read(fd2,buffer,sizeof(buffer))>0){
printf("%s",buffer);
if(write(fd2,buffer,sizeof(buffer))<0){
printf("send error!\n");
exit(1);
}
}
}
exit(0);
}
if(close(fd2) == -1){
printf("close error!\n");
exit(1);
}
}
}
几个主要函数说明:
socket()函数,创建套接口,返回套接口句柄。
bind()函数,
listen()函数,
htonl()和htons()
accept()
数据包在应用层称为data,在TCP层称为segment,在IP层称为packet,在数据链路层称为frame。