关键词不能为空

当前您在: 主页 > 英语 >

linux c c 开发重要函数应用积累0

作者:高考题库网
来源:https://www.bjmy2z.cn/gaokao
2021-02-11 22:03
tags:

-

2021年2月11日发(作者:moncler怎么读)


tcdrain()


函数


< br>标准


C


语言


tcdrain(f d)



等待直到所有写入



fd



引用的对象的输出都被传输



fcntl()


函数



#include



定义函数




int fcntl(int fd , int cmd);



int fcntl(int fd,int cmd,long arg);



int fcntl(int fd,int cmd,struct flock * lock);



fcntl()


用来操作

< p>
文件描述符


的一些特性。



参数


fd


代表欲设置的文件描述词。



参数


cmd


代表欲操作的指令。






有以下几种情况


:



F_DUPFD


用来查找大于或等于参数


arg


的最小且仍未使用的文件描述词,并且复制参数


fd

< br>的文


件描述词。执行成功则返回新复制的文件描述词。请参考

dup2()




F_GETFD


取得


close- on-exec


旗标。



若此旗标的< /p>


FD_CLOEXEC


位为


0

< p>
,代表在调用


exec()


相关函数时文件将不会 关闭。






F_SETFD


设置


close- on-exec


旗标。该旗标以参数


arg



FD_CLOEXEC


位决定。





F_GETFL


取得文件描述词状态旗标,此旗标为


open


()的参数


flags







F_SETFL


设置文件描述词状 态旗标,参数


arg


为新旗标,但只允许


O_APPEND



O_NONBLOCK

< br>和


O_ASYNC


位的改变,其他位的改变将不受影响。






F_GETLK


取得文件锁定的状态。




F_SETLK


设置文件锁定的状态。



此时


flcok


结构的


l_type


值必须是


F_RDLCK



F_WRLCK

< p>


F_UNLCK


。如果无法建立


锁定,则返回


-1


,错误代码为


EACCES



EAGAIN


。< /p>






F_SETLKW



F_SETLK


作用相同,


但是无法建立锁定时,


此调 用会一直等到锁定动作成功为止。


若在等待锁定的过程中被信号中断时,会立即返回


-1


,错误代码为


EINTR




参数


lock


指针为


flock


结构指针,定义如下






struct flcok





{







short int l_type;







short int l_whence;







off_t l_start;







off_t l_len;







pid_t l_pid;





};





l_type


有三种状态


:





F_RDLCK


建立一个供读取用的锁定






F_WRLCK


建立一个供写入用的锁定






F_UNLCK


删除之前建立的锁定






l_whence


也有三种方式


:





SEEK_SET


以文件开头为锁定的起始位置。






SEEK_CUR


以目前文件读写位置为锁定的起始位置






SEEK_END


以文件结尾为锁定的起始位置。




返回值



成功则返回

< br>0


,若有错误则返回


-1


,错误 原因存于


errno.


ioctl()


函数





一、


ioctl


是设备驱动程序中对 设备的


I/O


通道进行管理的函数。



所谓对


I/O


通道进行管理,就是对设 备的一些特性进行控制,例如串口的传输波特率、马达的转速等


等。它的调用形式如下:







int ioctl(int fd, ind cmd, …)








其中


fd


就是用户程序打开设备时使用


open

函数返回的文件标示符,


cmd


就是用户程序对设备的控制


命令,至于后面的省略号,那是一些补充参数,


一般最多一个, 有或没有是和


cmd


的意义相关的。






ioctl


函数是文件结构中的一个


属性分量

< br>,就是说如果你的驱动程序提供了对


ioctl


的支



持,用户就可以在用户程序中使用


ioc tl


函数控制设备的


I/O


通道。







二、



ioctl


的必要性







如果不用


ioctl


的话,也可以实现 对设备


I/O


通道的控制,但那就是蛮拧了。例如,我们可以在


驱动程


序中实现


write

< p>
的时候


检查一下是否有特殊约定的数据流通过,


如 果有的话,


那么后面就跟着控制命令


(一


般在


socket


编程中常常这样做)


。但是如果这样做的话,会导致代码分工不明,程序结构混乱,程序员自


己也会头昏眼 花的。







所以,我们就使用

< p>
ioctl


来实现控制的功能。要记住,用户程序所作的只是通过命令码告 诉驱动程序它


想做什么,至于怎么解释这些命令和怎么实现这些命令,这都是驱动程序要 做的事情。







三、



ioctl


如何实现







这是一个很麻烦的问题,我是能省则省。要说清楚它,没有四五千字是不行的,所以我这 里是不可能


把它说得非常清楚了,不过如果有读者对用户程序怎么和驱动程序联系起来感 兴趣的话,可以看我前一阵


子写的《


write


的奥秘》


。读者只要把


write

换成


ioctl


,就知道用户程序的


ioctl


是怎么和驱动程序中的


ioctl


实现联系在一起的了。







我这里说一个大概思路,因为 我觉得《


Linux


设备驱动程序》这本书已经说的非常清楚了 ,但是得花


一些时间来看。







在驱动程序中实现的


ioctl


函数体内,实际上是有一个


switch{case}


结构,每一个


c ase


对应一个命令


码,做出一些相应的操作。怎么实现这些操 作,这是每一个程序员自己的事情,因为设备都是特定的,这


里也没法说。



关键在于怎么样组织命令码,


因为在


ioctl



命令码是唯一联系用户程序命令和驱动 程序支持的途径。


命令码的组织是有一些讲究的,因为我们一定要做到命令和设备是一一 对应的,这样才不会将正确的命令


发给错误的设备,或者是把错误的命令发给正确的设备 ,或者是把错误的命令发给错误的设备。这些错误


都会导致不可预料的事情发生,而当程 序员发现了这些奇怪的事情的时候,再来调试程序查找错误,那将


是非常困难的事情。< /p>







所以在


Linux

< br>核心中是这样定义一个命令码的:






____________________________________




|


设备类型



|


序列号



|


方向



|


数据尺寸


|




|---------- -----|------------|---------|------------|




| 8 bit





| 8 bit




|2 bit



|8~14 bit|




|---------------|------- -----|---------|------------|





这样一来,一个命令就变成了 一个整数形式的命令码。但是命令码非常的不直观,所以


Linux

< br>Kernel


中提供了一些宏,这些宏可根据便于理解的字符串生成命令码,或者 是从命令码得到一些用户可以理解的


字符串以标明这个命令对应的设备类型、设备序列号 、数据传送方向和数据传输尺寸。






这些宏我就不在这里解释了, 具体的形式请读者察看


Linux


核心源代码中的文件里给出了 这些宏完整


的定义。这里我只多说一个地方,那就是


< p>
幻数



。幻数是一个字母,数据长度也是

< p>
8


,所以就用一个特定的


字母来标明设备类型,这 和用一个数字是一样的,只是更加利于记忆和理解。就是这样,再没有更复杂的


了。








更多的说了也没有,读者还是看一 看源代码吧,推荐各位阅读《


Linux


设备驱动程序》所带 源代码中



short


一例,因为它比 较短小,功能比较简单,可以看明白


ioctl


的功能和细节。







四、


cmd


参数如何得出







这里确实要说一说,


cmd


参数在用户程序端由一些宏根据设备类型、序列号、传送方向、数 据尺寸等


生成,这个整数通过系统调用传递到内核中的驱动程序,再由驱动程序使用解码 宏从这个整数中得到设备


的类型、序列号、传送方向、数据尺寸等信息,然后通过





switch{case}


结构进行相应的操作。







要透彻理解,只能是通过阅读源代码,我这篇文章实际上只是一个引子。


Cmd


参数的组织还是比较复


杂的,我认为要搞熟它还 是得花不少时间的,但是这是值得的,驱动程序中最难的是对中断的理解。







五、小结






ioctl


其实没有什么很难 的东西需要理解,


关键是理解


cmd


命 令码是怎么在用户程序里生成并在驱动程


序里解析的,


程序员最 主要的工作量在


switch{case}


结构中,

< p>
因为对设备的


I/O


控制都是通过这一部分的代< /p>


码实现的。




flock()


函数



当用户想使用函数


flock()


来锁定一个文件时, 可以使用两种不同的锁定类型:一个是共享锁定,另


一个是互斥锁定。如果用户采用共享 锁定,若干个进程可以对某个文件拥有一个共同的锁定;如果用户申


请了一个互斥锁定, 其他进程都无法对该文件进行锁定。因此,根据它们的原理,用户可以对执行


读取操



的系统采用一个共享锁定,而对执行


写入 操作


的系统采用一个互斥锁定。


(摘自《


Linux


编程宝典》





那么我就有疑问了


:


1.


既然读取操作的时候是不会对文件内容进行改变的 ,各个进程是不会相互冲突的,那么为什么要锁


定?锁定的意义何在?

< br>


2.


读取操作的时候使用共享锁定,也就是 说,其它进程也可以锁定,那么是不是进行写操作的进程也


可以锁定也可以写入呢?共享 锁定没有什么作用?



1.



2.



若干进程在读,他们不会互相影 响,但是,如果有进程写则会影响它们,所以这个共享锁是防


止有进程对文件写



第二个问题和第一个问题关联,共享锁和独占锁互斥。


只有当一个程序试图施加它自己的锁


时,锁才会起作用;而没有尝试对文件上 锁的程序仍然能够访问该文件。因此,锁只能在协


同工作的程序间起作用。


”(摘自《


GNU/Linux


编程指南》




3.


< p>
据程序试验结果:


当我对一个文件进行互斥锁定以后,

然后进行共享锁定时,


锁定没有成功——


这是因为互斥锁定 是排斥其他锁定的;


当我对一个文件进行共享锁定以后,


然后进 行互斥锁定,


锁定成功!——难道互斥锁定不排斥之前的共享锁定?

请解答。



4.



我错在先关闭了文件描述符,


当然共享锁定也就关闭了,


随之互斥锁定必然也就能够成功,



错了,不好意思。但是, 据我试验:如果一个进程对文件进行了互斥锁定,另外一个进程没有


对文件进行尝试锁定 操作而是直接对文件进行写操作,结果是可以写入!?




5.



6.



那么也就是说,


如果进程没有考虑到锁定的问题时,

< p>
还是会破坏我锁定想保持不变的文件?那


么这个锁定的意义是不是大打折扣 了?




呵呵!


这样的锁叫建议锁和建议一样



可听可不听



好像还有强制锁



不过我没用过



呵呵



APUE


上有介绍。


如果你和别的程序混用无法控制他们的话,


建议你 采用


QMAIL


一样的原子操作法,


不 需要锁。



UART



CTS



RTS




RS232


中本来


C TS




RTS



有 明确的意义,


但自从贺氏


(


HAYES



)


推出了聪明猫

< br>(SmartModem)


后就有点混淆了。



RS232



RTS




CTS



是用来半双工模式下的方向切换;


HAYES Modem


中的


RTS




CTS



是用来进



行硬件流控的。通常


UART



RTC



CTS



的含义指后者,即用来做硬流控的。



硬流控的


RTS




CTS




RTS




Require To Send


, 发送请求)为输出信号,用于指示本设备准备


好可接收;


CTS




Clear To Send


,发送清除)为输入信号,有效时停止发送。假定


A



B


两设备通信,


A


设备的


RTS



连接< /p>


B


设备的


CTS




A


设备的


C TS



连接


B


设备




RTS





前一路信号控制

< br>B


设备的发


送,后一路信号控制


A


设备的发送。对


B


设备的发送(


A


设备接收)来说,如果


A


设备接收缓冲快满的时


发出


RTS


信号(意思



通知


B


设备停止发送),


B


设备 通过


CTS



检测到该信号,停止发送 ;一段时间后


A


设备接收缓冲有了空余,发出

< br>RTS



信号,指示


B


设备开始发送数据。


A


设备发(


B


设备接收)



类似。


上述功能也能在数据流中插入


Xoff


(特殊 字符)和


Xon


(另一个特殊字符)信号来实现。


A


设备一旦接收



B


设备发送过来的


Xoff


,立刻停止发



送;反之,如接收到


B

设备发送过来的


Xon


,则恢复发送数据给


B


设备。同理,


B


设备也类似 ,从而实现收发双方的速度匹配。



半双工的方向切换:


RS232


中使用


DTR


Date Terminal Ready


,数据终端准 备)与


DSR



Data


Set Ready


,数据设备准备好)进行主流控,类似上 述的


RTS




CTS



。 对半双工的通信的


DTE



Date


Terminal Equipment


,数据终端设备)与< /p>


DCE



Data circuit Equipment


)来说,默认的方向是


DTE

< p>
接收,


DCE


发送。如果


DTE


要发送数据,必须发出


RTS



信号,请求发送数据。


DCE


收到后如 果



空闲则


发出


CTS






RTS





号,表示响应请求,这样通信方向 就变为


DTE->TCE


,同时


RTS




CTS



信号


必须一直保持。从这里可以看出,


CTS




TRS

虽然也有点流控的意思(如


CTS


没有发出,


DTE


也不能发


送数据),但主要是用来进行方向切 换的。



如果


UART


只有


RX



TX


两个信号,要流控的话只能是软流控;如果有


RX



TX



CTS




RTS



四 个


信号,


则多半是支持硬流控的


UAR T



如果有



RX



TX



CTS




RTS




DTR



DSR

六个信号的话,


RS232


标准的可能性比较大。



顺便提一下:



DCD




Data Carrier Detect




数据载波检测):< /p>


DCE



DTE


指示,线路上检测到载波。



RI



Ring Indicator


,振铃指示):


DCE



DTE


指示,有呼叫接入。




linux


基础复习(

< p>
7


)串口应用开发



据通信的基本方式可分为并行通信与串行通信两种。



·



并行通信是指利用多条数据传输线 将一个资料的各位同时传送。它的特点是传输速度



快,适用于短距离通信,但要求传输速度较高的应用场合。



·



串行通信是指利用一条传输线将资 料一位位地顺序传送。特点是通信线路简单,利用



简单的线缆 就可实现通信,降低成本,适用于远距离通信,但传输速度慢的应用场合。



串口设置详解



本节主要讲解设置串口的主要方法。



如前所述,设置串口中最基本的包括波特率设置,校验位和停止位设置。串口的设置主要是设置

< br>struct termios


结构体的各


成员值,如下 所示:




include


struct termio


{






unsigned short c_iflag; /*


输入模式标志



*/




unsigned short c_oflag; /*


输出模式标志



*/




unsigned short c_cflag; /*


控制模式标志


*/




unsigned short c_lflag; /*


本地模式标志



*/




unsigned char c_line; /* line discipline */




unsigned char c_cc[NCC]; /* control characters */


};


在这个结构中最为重要的是


c_cflag


,通过对它的赋值, 用户可以设置波特率、字符大小、



数据位、停止位、奇偶校验 位和硬件流控等。另外


c_iflag



c_cc


也是比较常用的标志。在



此主要对这


3


个成员进行详细说明。








c_cflag


支持的常量名称



CBAUD




波特率的位掩码



B0




0


波特率(放弃


DTR




B1800



1800


波特率



B2400



2400


波特率



B4800



4800


波特率



B9600



9600


波特率



B19200




19200


波特率



B38400




38400


波特率



B57600




57600


波特率



B115200



115200


波特率



EXTA





外部时钟率



EXTB





外部时钟率



CSIZE




数据位的位掩码



CS5





5


个数据位



CS6





6


个数据位



CS7





7


个数据位



CS8





8


个数据位



CSTOPB




2


个停止位(不设则是


1


个停止位)



CREAD




接收使能



PARENB




校验位使能



PARODD




使用奇校验而不使用偶校验



HUPCL




最后关闭时挂线(放弃


DTR




CLOCAL




本地连接(不改变端口所有者)



LOBLK




块作业控制输出



CNET_CTSRTS


硬件流控制使能



c_iflag


支持的常量名称



INPCK




奇偶校验使能



IGNPAR




忽略奇偶校验错误



PARMRK




奇偶校验错误掩码



ISTRIP




除去奇偶校验位



IXON





启动出口硬件流控



IXOFF




启动入口软件流控



IXANY




允许字符重新启动流控



IGNBRK




忽略中断情况



BRKINT




当发生中断时发送


SIGINT


信号



INLCR





NL


映射到


CR


IGNCR




忽略


CR


ICRNL





CR


映射到


NL


IUCLC




将高位情况映射到低位情况



IMAXBEL




当输入太长时回复


ECHO


c_cc


支持的常量名称



VINTR



中断控制,对应键为


CTRL+C


VQUIT



退出操作,对应键为


CRTL+Z


VERASE



删除操作,对应 键为


Backspace



BS




VKILL



删除行,对应键为


CTRL+U


VEOF




位于文件结尾,对应键为


CTRL+D


VEOL




位于行尾,对应键为


Carriage return



CR




VEOL2



位于第二行尾,对应键为


Line feed

< br>(


LF




VMIN




指定了最少读取的字符数



VTIME



指定了读取每个字符的等待时间



串口控制函数



Tcgetattr





取属性


(termios


结构


)


Tcsetattr





设置属性


(termios


结构


)


cfgetispeed



得到输入速度



Cfgetospeed





得到输出速度



Cfsetispeed






设置输入速度



Cfsetospeed





设置输出速度



Tcdrain





等待所有输出都被传输



tcflow





挂起传输或接收



tcflush





刷清未决输入和


/


或输出



Tcsendbreak




< br>送


BREAK


字符



tcgetpgrp






得到前台进程组


ID


tcsetpgrp







设置前台进程组


ID


完整的串口配置 模板,实用!把常用的选项在函数里面列出,可大大方便用户的调试使用



int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)


{




struct termios newtio,oldtio;



< /p>


/*


保存测试现有串口参数设置,在这里如果串口号等出错,会有 相关的出错信息


*/




if ( tcgetattr( fd,&oldtio) != 0)




{




perror(





return -1;



}




bzero( &newtio, sizeof( newtio ) );




/*


步骤一,设置字符大小


*/




newtio.c_cflag |= CLOCAL | CREAD;




newtio.c_cflag &= ~CSIZE;




/*


设置停止位


*/




switch( nBits )




{




case 7:






newtio.c_cflag |= CS7;






break;




case 8:






newtio.c_cflag |= CS8;

-


-


-


-


-


-


-


-



本文更新与2021-02-11 22:03,由作者提供,不代表本网站立场,转载请注明出处:https://www.bjmy2z.cn/gaokao/639283.html

linux c c 开发重要函数应用积累0的相关文章