姓名:楊喬 ? 學(xué)號:19020100280 ?? 學(xué)院:電子工程學(xué)院
轉(zhuǎn)自:
https://blog.csdn.net/qq_41035588/article/details/92002740
【嵌牛導(dǎo)讀】嵌入式一般指嵌入式系統(tǒng)。嵌入式系統(tǒng)由硬件和軟件組成。是能夠獨立進行運作的器件。Linux,全稱GNU/Linux,是一種免費使用和自由傳播的類UNIX操作系統(tǒng),其內(nèi)核由林納斯·本納第克特·托瓦茲于1991年10月5日首次發(fā)布,它主要受到Minix和Unix思想的啟發(fā),是一個基于POSIX的多用戶、多任務(wù)、支持多線程和多CPU的操作系統(tǒng)。
【嵌牛鼻子】基于ARM的嵌入式Linux開發(fā)總結(jié)
【嵌牛提問】基于ARM的嵌入式Linux開發(fā)如何使用?
【嵌牛正文】
一、Linux進程編程
進程(Process)是計算機中的程序關(guān)于某數(shù)據(jù)集合上的一次運行活動,是操作系統(tǒng)進行資源分配和調(diào)度的基本單位,是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ)。
1 進程控制
?子進程創(chuàng)建:fork()函數(shù)
在Linux中創(chuàng)建一個新進程的唯一方法是使用fork()函數(shù)。fork()函數(shù)是Linux中一個非常重要的函數(shù),和以往遇到的函數(shù)有一些區(qū)別,因為fork()函數(shù)看起來執(zhí)行一次卻返回兩個值。
1)fork()函數(shù)說明
fork()函數(shù)用于從已存在的進程中創(chuàng)建一個新進程。新進程稱為子進程,而原進程稱為父進程。
使用fork()函數(shù)得到的子進程是父進程的一個復(fù)制品,它從父進程處繼承了整個進程的地址空間,包括進程的上下文、代碼段、進程堆棧、內(nèi)存信息、打開的文件描述符、符號控制設(shè)定、進程優(yōu)先級、進程組號、當(dāng)前工作目錄、根目錄、資源限制和控制終端等,而子進程所獨有的只有它的進程號、資源使用和計時器等。
因為子進程幾乎是父進程的完全復(fù)制,所以父子兩進程會運行同一個程序。這就需要用一種方式來區(qū)分它們,并使它們照此運行,否則,這兩個進程不可能做不同的事。
實際上是在父進程中執(zhí)行fork()函數(shù)時,父進程會復(fù)制一個子進程,而且父子進程的代碼從fork()函數(shù)的返回開始分別在兩個地址空間中同時運行,從而使兩個進程分別獲得所屬fork()函數(shù)的返回值,其中在父進程中的返回值是子進程的進程號,而在子進程中返回0。因此,可以通過返回值來判斷該進程的父進程還是子進程。
2)fork()函數(shù)語法
?進程等待函數(shù)
1)wait()函數(shù),無條件等待,父進程阻塞直到子進程結(jié)束
2)waitpid()函數(shù),指定等待某個子進程結(jié)束以及等待的方式(阻塞或非阻塞)
所需頭文件 #include <sys/types.h>
#include <sys/wait.h>
函數(shù)原型 pid_t waitpid(pid_t pid, int *status, int options)
函數(shù)參數(shù) pid pid>0:只等待進程ID等于pid的子進程,不管已經(jīng)有其他子進程運行結(jié)束退出了,只要指定的子進程還沒有結(jié)束,waitpid就會一直等下去。
pid=-1:等待任何一個子進程退出,此時和wait作用一樣。
pid=0:等待其組ID等于調(diào)用進程的組ID的任一子進程。
pid<-1:等待其組ID等于pid的絕對值的任一子進程。
status 同wait
options WNOHANG:若由pid指定的子進程并不立即可用,則waitpid不阻塞,此時返回值為0
WUNTRACED:若某實現(xiàn)支持作業(yè)控制,則由pid指定的任一子進程狀態(tài)已暫停,且其狀態(tài)自暫停以來還未報告過,則返回其狀態(tài)。
0:同wait,阻塞父進程,等待子進程退出。
函數(shù)返回值 正常:結(jié)束的子進程的進程號
使用選項WNOHANG且沒有子進程結(jié)束時:0
調(diào)用出錯:-1
所需頭文件 #include <sys/types.h>
#include <sys/wait.h>
函數(shù)原型 pid_t waitpid(pid_t pid, int *status, int options)
函數(shù)參數(shù) pid pid>0:只等待進程ID等于pid的子進程,不管已經(jīng)有其他子進程運行結(jié)束退出了,只要指定的子進程還沒有結(jié)束,waitpid就會一直等下去。
pid=-1:等待任何一個子進程退出,此時和wait作用一樣。
pid=0:等待其組ID等于調(diào)用進程的組ID的任一子進程。
pid<-1:等待其組ID等于pid的絕對值的任一子進程。
status 同wait
options WNOHANG:若由pid指定的子進程并不立即可用,則waitpid不阻塞,此時返回值為0
WUNTRACED:若某實現(xiàn)支持作業(yè)控制,則由pid指定的任一子進程狀態(tài)已暫停,且其狀態(tài)自暫停以來還未報告過,則返回其狀態(tài)。
0:同wait,阻塞父進程,等待子進程退出。
函數(shù)返回值 正常:結(jié)束的子進程的進程號
使用選項WNOHANG且沒有子進程結(jié)束時:0
調(diào)用出錯:-1
?進程結(jié)束:exit()和_exit()
所需頭文件 exit:#include <stdlib.h>
_exit:#include <unistd.h>
函數(shù)原型 exit:void exit(int status);
_exit:void _exit(int status);
函數(shù)傳入值 status是一個整型的參數(shù),可以利用這個參數(shù)傳遞進程結(jié)束時的狀態(tài)。
通常0表示正常結(jié)束;其他的數(shù)值表示出現(xiàn)了錯誤,進程非正常結(jié)束。
在實際編程時,可以用wait系統(tǒng)調(diào)用接收子進程的返回值,進行相應(yīng)的
處理。
所需頭文件 exit:#include <stdlib.h>
_exit:#include <unistd.h>
函數(shù)原型 exit:void exit(int status);
_exit:void _exit(int status);
函數(shù)傳入值 status是一個整型的參數(shù),可以利用這個參數(shù)傳遞進程結(jié)束時的狀態(tài)。
通常0表示正常結(jié)束;其他的數(shù)值表示出現(xiàn)了錯誤,進程非正常結(jié)束。
在實際編程時,可以用wait系統(tǒng)調(diào)用接收子進程的返回值,進行相應(yīng)的
處理。
兩者的區(qū)別:
(1)_exit()函數(shù)的作用最為簡單:直接使進程終止運行,清除其使用的內(nèi)存空間,并銷毀其在內(nèi)核中的各種數(shù)據(jù)結(jié)構(gòu);
(2)exit()函數(shù)則在這些基礎(chǔ)上作了一些包裝,在執(zhí)行退出之前加了若干道工序。
(3)exit()函數(shù)在調(diào)用exit系統(tǒng)調(diào)用之前要檢查文件的打開情況,把文件緩沖區(qū)中的內(nèi)容寫回文件,就是"清理I/O緩沖"。
?Linux下的進程間通信
進程間通信用于實現(xiàn)參數(shù)傳遞及通信功能;Linux支持的常用的進程間通信方法:管道、消息隊列、共享內(nèi)存、信號量、套接口等等。
實例:(1)實驗三:Linux進程編程;
(2)網(wǎng)盤linux編程源代碼目錄下fork文件下相關(guān)實例(FIFO、msgque、shm)。
嵌入式知識點復(fù)習(xí)六 --arm-linux網(wǎng)絡(luò)編程
1、程序流程
(1)網(wǎng)絡(luò)通信程序架構(gòu)-客戶端/服務(wù)器架構(gòu)
2、函數(shù)說明
?socket()
Sockfd=socket(AF_INET,SOCK_STREAM,0);
?Bind()
s_add.sin_family=AF_INET;IPV4協(xié)議
s_add.sin_addr.s_addr=inet_addr(“192.168.1.123”);IP地址192.168.1.123
s_add.sin_port=htons(0x8888);端口號是8888
if(-1 == bind(Sockfd,(struct sockaddr *)(&s_add), sizeof(struct sockaddr)))
?listen()服務(wù)器端偵聽函數(shù)
listen(Sockfd,5)服務(wù)器偵聽來自客戶端的請求
?accept()服務(wù)器端接受客戶端連接請求
nfp = accept(Sockfd, (struct sockaddr *)(&c_add), sizeof(struct sockaddr);
?send()數(shù)據(jù)發(fā)送函數(shù)
send(nfp,“hello,welcome to my server”,32,0)
?recv()數(shù)據(jù)接收函數(shù)
recv(nfp,buffer,1024,0)
?關(guān)閉連接
Close(nfp)
?關(guān)閉服務(wù)器
Close(Sockfd)
實例:(1)實驗四:網(wǎng)絡(luò)聊天室設(shè)計
(2)網(wǎng)盤/linux編程源代碼/socket下相關(guān)代碼
嵌入式知識點復(fù)習(xí)七 --linux字符型設(shè)備驅(qū)動初步
一、Linux字符設(shè)備驅(qū)動初步
1、Linux設(shè)備類型
(1)字符設(shè)備:只能一個字節(jié)一個字節(jié)的讀寫的設(shè)備,不能隨機讀取設(shè)備內(nèi)存中的某一數(shù)據(jù),讀取數(shù)據(jù)需要按照先后順序進行。字符設(shè)備是面向流的設(shè)備,常見的字符設(shè)備如鼠標(biāo)、鍵盤、串口、控制臺、LED等。
(2)塊設(shè)備:是指可以從設(shè)備的任意位置讀取一定長度的數(shù)據(jù)設(shè)備。塊設(shè)備如硬盤、磁盤、U盤和SD卡等存儲設(shè)備。
(3)網(wǎng)絡(luò)設(shè)備:網(wǎng)絡(luò)設(shè)備比較特殊,不在是對文件進行操作,而是由專門的網(wǎng)絡(luò)接口來實現(xiàn)。應(yīng)用程序不能直接訪問網(wǎng)絡(luò)設(shè)備驅(qū)動程序。在/dev目錄下也沒有文件來表示網(wǎng)絡(luò)設(shè)備。
2、開發(fā)流程
3、關(guān)鍵函數(shù)講解(以2.6以下版本內(nèi)核為例)
(1)驅(qū)動模塊注冊register_chrdev()函數(shù)
原型:register_chrdev(unsigned int major, const char *name,const struct file_operations *fops);
major:主設(shè)備號,該值為 0 時,自動運行分配。而實際值不是 0 ;
name:設(shè)備名稱;
fops:操作函數(shù),實現(xiàn)驅(qū)動定義的open、read、write、close等內(nèi)核函數(shù)與應(yīng)用程序調(diào)用的open、read、write、close間的映射;
返回值:
major 值為 0 ,正常注冊后,返回分配的主設(shè)備號。如果分配失敗,返回 EBUSY 的負值 ( -EBUSY ) 。major 值若大于 linux/major.h (2.4內(nèi)核)中聲明的最大值 (#define MAX_CHRDEV 255) ,則返回EINVAL 的負值 (-EINVAL) 。指定 major 值后,若有注冊的設(shè)備,返回 EBUSY 的負值 (-EBUSY)。若正常注冊,則返回 0 值
(2)驅(qū)動注銷unregister_chrdev()函數(shù)
原型:
#include <linux.fs.h>
int unregister_chrdev (unsigned int major, const char *name)
變量:
?major 主設(shè)備號
?name 設(shè)備文件
返回值:
major 值若大于 linux/major.h (2.4 內(nèi)核)中聲明的最大值 (#define MAX_CHRDEV 255),返回 EINVAL的負值 (-EINVAL)。指定了 major的值后,若將要注銷的 major 值并不是注冊的設(shè)備驅(qū)動程序,返回 EINVAL的負值 ( -EINVAL )。正常注銷則返回 0值。
(3)File_operation結(jié)構(gòu)體
file_operations結(jié)構(gòu)是建立驅(qū)動程序和設(shè)備編號的連接,內(nèi)部是一組函數(shù)指針,每個打開的文件,也就是file結(jié)構(gòu),和一組函數(shù)關(guān)聯(lián),這些操作主要用來實現(xiàn)系統(tǒng)調(diào)用的
struct file_operations {
struct module *owner;//擁有該結(jié)構(gòu)的模塊的指針,一般為THIS_MODULES
loff_t (*llseek) (struct file *, loff_t, int);//用來修改文件當(dāng)前的讀寫位置
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);//從設(shè)備中同步讀取數(shù)據(jù)
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);//向設(shè)備發(fā)送數(shù)據(jù)
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);//初始化一個異步的讀取操作
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);//初始化一個異步的寫入操作
int (*readdir) (struct file *, void *, filldir_t);//僅用于讀取目錄,對于設(shè)備文件,該字段為NULL
unsigned int (*poll) (struct file *, struct poll_table_struct *); //輪詢函數(shù),判斷目前是否可以進行非阻塞的讀寫或?qū)懭?/p>
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); //執(zhí)行設(shè)備I/O控制命令
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); //不使用BLK文件系統(tǒng),將使用此種函數(shù)指針代替ioctl
long (*compat_ioctl) (struct file *, unsigned int, unsigned long); //在64位系統(tǒng)上,32位的ioctl調(diào)用將使用此函數(shù)指針代替
int (*mmap) (struct file *, struct vm_area_struct *); //用于請求將設(shè)備內(nèi)存映射到進程地址空間
int (*open) (struct inode *, struct file *); //打開
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *); //關(guān)閉
int (*fsync) (struct file *, struct dentry *, int datasync); //刷新待處理的數(shù)據(jù)
int (*aio_fsync) (struct kiocb *, int datasync); //異步刷新待處理的數(shù)據(jù)
int (*fasync) (int, struct file *, int); //通知設(shè)備FASYNC標(biāo)志發(fā)生變化
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
};