在Linux下一切資源皆文件,普通文件是文件,磁碟列印機是文件,socket 當然也是文件。
關於Linux下系統,進程能最大能打開的文件描述符數看過好多文章,但大都沒有完整,詳細說明每個值表示什麼意思,在實踐中該怎麼設置?
如何通過最簡單的設置來實現最有效的性能調優,如何在有限資源的條件下保證程序的運作?
max-file 表示系統級別的能夠打開的文件句柄的數量,是對整個系統的限制,並不是針對用戶的。
ulimit -n 控制進程級別能夠打開的文件句柄的數量,提供對shell及其啟動的進程的可用文件句柄的控制,這是進程級別的。
對於伺服器來說,file-max和ulimit都需要設置,否則會出現文件描述符耗盡的問題。
一般如果遇到文件句柄達到上限時,會碰到"Too many open files"或者Socket/File: Can』t open so many files等錯誤。
相關的3個文件:
/proc/sys/fs/file-max
/proc/sys/fs/file-nr
/etc/security/limits.conf
/proc/sys/fs/file-max
Linux系統級別限制所有用戶進程能打開的文件描述符總數。
max-file 表示系統級別的能夠打開的文件句柄的數量,是對整個系統的限制,並不是針對用戶的。
/etc/security/limits.conf
用戶級別的限制是通過可以通過命令ulimit命令和文件/etc/security/limits.conf
/proc/sys/fs/file-nr 該參數是只讀的,不能修改。
file-nr的值由3部分組成:
1,已經分配的文件描述符數;
2,已經分配但未使用的文件描述符數;
3,內核最大能分配的文件描述符數
/proc/${pid}/fd
眾所周知,在相應進程的/proc/$pid/fd 目錄下存放了此進程所有打開的fd。
當然有些可能不是本進程自己打開的,如通過fork()從父進程繼承而來的。
那麼這個socket:後面的一串數字是什麼呢?其實是該socket的inode號。
那麼,知道了某個進程打開的socket的inode號後,我們可以做什麼呢?
這就涉及到/proc/net/tcp(udp對應/proc/net/udp)文件了,其中也列出了相應socket的inode號通過比對此欄位,我們能在/proc/net/tcp下獲得此套介面的其他信息,如對應的<本地地址:埠號,遠端地址:埠號>對,窗口大小,狀態等信息。
具體欄位含義詳見net/ipv4/tcp_ipv4.c 中的 tcp4_seq_show 函數。
如果socket創建了,沒有被使用,那麼就只會在/proc/pid/fd下面有,而不會在/proc/net/下面有相關數據。
目錄中的每一項都是一個符號鏈接,指向打開的文件,數字則代表文件描述符。
其中0 = /dev/null ,1 = stdout, 2 = stderr,用cat或tail查看即可。
Number of file descriptors: different between /proc/sys/fs/file-nr and /proc/$pid/fd?
https://serverfault.com/questions/485262/number-of-file-descriptors-different-between-proc-sys-fs-file-nr-and-proc-pi
Linux中最大文件描述符數
https://leokongwq.github.io/2016/11/09/linux-max-fd.html
How do linux file descriptor limits work?
https://stackoverflow.com/questions/3991223/how-do-linux-file-descriptor-limits-work
limits.conf(5) - Linux man page
https://linux.die.net/man/5/limits.conf
Why can't I tail -f /proc/$pid/fd/1 ?
https://unix.stackexchange.com/questions/152773/why-cant-i-tail-f-proc-pid-fd-1
Linux查看進程運行輸出(/proc/<pid>/fd)
https://blog.csdn.net/u014756245/article/details/120023188
B. Linux 裡面重復創建socket 與 串口 返迴文件描述符都為0怎麼辦 相互影響嗎
你想問的東西可能很簡單,可是你對問題的描述讓我無法幫助你
socket斷線?
不可能返回描述符為0的,有錯誤會返回-1,0是標准輸入的文件描述符哦
C. linux文件描述符
Linux 下,一切皆文件
在Linux操作系統中,可以將一切都看作是文件,包括普通文件,目錄文件,字元設備文件(如鍵盤,滑鼠…),塊設備文件(如硬碟,光碟機…),套接字等等,所有一切均抽象成文件,提供了統一的介面,方便應用程序調用。
既然在Linux操作系統中,你將一切都抽象為了文件,那麼對於一個打開的文件,我應用程序怎麼對應上呢?
文件描述符應運而生。
文件描述符:File descriptor,簡稱fd,當應用程序請求內核打開/新建一個文件時,內核會返回一個文件描述符用於對應這個打開/新建的文件,其fd本質上就是一個 非負整數 。實際上,它是一個索引值,指向 內核為每一個進程所維護的該進程打開文件的記錄表。當程序打開一個現有文件或者創建一個新文件時,內核向進程返回一個文件描述符。 在程序設計中,一些涉及底層的程序編寫往往會圍繞著文件描述符展開。但是文件描述符這一概念往往只適用於UNIX、Linux這樣的操作系統。
操作系統的核心叫內核,是一個獨立的軟體。
操作系統為每一個進程維護了一個文件描述符表,該表的索引值都從從0開始的,所以在不同的進程中可以看到相同的文件描述符,這種情況下相同的文件描述符可能指向同一個文件,也可能指向不同的文件,具體情況需要具體分析,下面用一張簡圖就可以很容易的明白了。
通過上圖可以看到,當不同進程中出現相同的文件描述符時,可能實際對應的文件並不是同一個,相反不同進程中不同的文件描述符也可可能對應同一個文件。
當一個應用程序剛剛啟動的時候,0是標准輸入,1是標准輸出,2是標准錯誤。如果此時去打開一個新的文件,它的文件描述符會是3。POSIX標准要求每次打開文件時(含socket)必須使用當前進程中最小可用的文件描述符號。
文件描述符是一個重要的系統資源,理論上系統內存多大就應該可以打開多少個文件描述符,但是實際情況是,內核會有系統級限制,以及用戶級限制(不讓某一個應用程序進程消耗掉所有的文件資源,可以使用ulimit -n 查看)。
進程 + 文件描述符ID確認,因為內核為每個進程都有一份其所屬的文件描述符表。
所以linux下兩個進程返回的文件描述符是不一樣的
多個進程之間的fd:
應用程序進程拿到的 文件描述符ID 對應 進程文件描述符表 的索引,通過索引拿到 文件指針 ,指向系統級文件描述符表的 文件偏移量 ,再通過文件偏移量找到 inode指針 ,最終對應到真實的文件。
D. linux串口讀取問題
首先你確定你那串口是否有東西可讀? 就是你上面說的「一個文件不停的寫數據到串口」!你版可以先不這樣權讀取,你可以在終端上用cat試試是否有數據可讀:cat /dev/ttyS0
如果有的話,那你就檢查串口設置是否正確,如波特率,數據位,停止位,校驗位等!
最後就是你讀取的函數了,看看先不要用printf列印字元串了,先看看十六進制是否有,然後再看字元等!
就是以上一些,你還可以參考Linux下串口文檔,網路上很多的……
E. Linux查看進程打開多少文件描述符命令
1、當linux打開一個文抄件的時候,Linux內核會為每一個進程在/proc/ 建立一個以其pid
為名的目錄用來保存進程的相關信息,而其子目錄fd保存的是該進程打開的所有文件的fd(fd:file descriptor)。
2、例如/proc/13844/fd/目錄(13844為pid)
3、ps -ef|grep java
root 13884 1 0 Aug15 ? 08:51:38 /doyoo/jdk1.8/bin/java
4、ll /proc/13884/fd
F. linux怎樣獲取文件描述符
打開一個文件就能獲得一個文件描述符
G. Linux C 配置串口
配置串口需要包含頭文件
其中最核心的配置結構體為:
如何獲取該結構呢?我們操作串口跟操作文件一樣,也是調用 open() 函數來打開串口,
這樣我們就能夠得到一個文件描述符 fd ,然後就可以調用 tcgetattr() 函數來獲取上述配置結構體了。
Linux 串口默認的配置為:波特率 9600,數據位 8 位,無奇偶校驗,停止位 1 位,無 CTS/RTS 。
以下介紹一些常用的配置項:波特率、奇偶校驗、數據位、停止位、硬體控制流。
相關介面:
Linux 將串口的波特率分為了輸入波特率和輸出波特率,不過最常用的場景是將兩者設置成一樣。
cfgetispeed() 函數獲取輸入波特率, cfgetospeed() 函數獲取輸出波特率。 cfsetispeed() 函數設置輸入波特率, cfsetospeed() 函數用於設置輸出波特率,當然 cfsetspeed() 函數擴展為同時設置輸入和輸出波特率。
上述介面中的 speed_t 是一系列波特率的標志位,例如常用的 115200 波特率就為 B115200,參考下述選項:
設置奇偶校驗位可以通過修改 termios 結構體中的 c_cflag 成員來實現,若無校驗,則將 PARENB 位設為 0;若有校驗,則 PARENB 為 1。之後再根據 PARODD 來區分奇偶校驗, PARODD 為 1 表示奇校驗, PARODD 為 0 表示偶校驗。例如設置無奇偶校驗位:
設置數據位可以通過修改 termios 結構體中的 c_cflag 成員來實現,CS5、CS6、CS7 和 CS8 分別代表數據位 5、6、7 和 8。不過在設置數據位之前,需要先用 CSIZE 來做屏蔽欄位,清楚這幾個標志位,例如設置數據位為 8 位:
設置停止位可以通過修改 termios 結構體中的 c_cflag 成員來實現, CSTOPB 位為 1 表示 2 位停止位, CSTOPB 位為 0 標志 1 位停止位。例如設置停止位為 1 位:
設置硬體控制流可以通過修改 termios 結構體中的 c_cflag 成員來實現, CRTSCTS 為 1 表示使用硬體控制流,為 0 表示不使用硬體控制流。例如使能硬體控制流:
當然,最後還需要用 tcflush() 拋棄存儲在 fd 里的未接收的數據。
再利用介面 tcsetattr() 函數將配置信息寫入文件描述符 fd :
這樣整個串口最常用的用法就配置完成了。
具體的配置使用可以參考我的項目 HCI-Middleware 里的 hci_transport_uart_linux.c 文件。
參考:
H. 請問程序中linux如何獲取可用的串口列表
|dmesg | grep tty
下面是一個例子,例子中採用的是USB轉串口線(pl2303)。
插入線:
$ dmesg|grep tty
[ 0.000000] console [tty0] enabled
[ 1.248404] serial8250: ttyS0 at I/O 0x3f8 (irq = 4) is a 16550A
[ 1.624590] 00:07: ttyS0 at I/O 0x3f8 (irq = 4) is a 16550A
[ 12.618301] usb 5-2: pl2303 converter now attached to ttyUSB0
拔出線:
$ dmesg|grep tty
[ 0.000000] console [tty0] enabled
[ 1.248404] serial8250: ttyS0 at I/O 0x3f8 (irq = 4) is a 16550A
[ 1.624590] 00:07: ttyS0 at I/O 0x3f8 (irq = 4) is a 16550A
[ 12.618301] usb 5-2: pl2303 converter now attached to ttyUSB0
[ 375.392303] pl2303 ttyUSB0: pl2303 converter now disconnected from ttyUSB0
這樣程序中應該不難判斷了吧。
【參考】http://www.cyberciti.biz/faq/find-out-linux-serial-ports-with-setserial/
I. 如何查看linux下串口是否可用串口名稱等
分析如下:
1、查看串口是否可用,可以對串口發送數據比如對com1口,echo lyjie126 > /dev/ttyS0。
2、查看串口名稱使用ls-l/dev/ttyS* 一般情況下串口的名稱全部在dev下面,如果你沒有外插串口卡的話默認是dev下的ttyS* ,一般ttyS0對應com1,ttyS1對應com2,當然也不一定是必然的;
3、查看串口驅動:cat /proc/tty/drivers/serial。
4、查看串口設備:dmesg | grep ttyS*。
(9)linux獲取串口的文件描述符擴展閱讀
串口控制器顧名思義,就是可通過串口實現控制功能的一台控制器。即由上位機通過串口發送特定協議格式的指令給控制器,進而來控制外圍設備或器件,也叫單片機串口控制器。
串口控制器就是1台寫入了串口通信程序的單片機控制器,有2種工作模式:
1)上位機監控模式:可由上位機串口控制,實現串口監控;
2)離線控制模式:在通過上位機設置好相關參數後,也可脫離上位機進行獨立控制。
串口控制器就是1台寫入了串口通信程序的單片機控制器,有2種工作模式:
1)上位機監控模式:可由上位機串口控制,實現串口監控;
2)離線控制模式:在通過上位機設置好相關參數後,也可脫離上位機進行獨立控制。
J. linux怎麼讀取串口數據
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<termios.h>
#include<errno.h>
#defineFALSE-1
#defineTRUE0
intspeed_arr[]={B38400,B19200,B9600,B4800,B2400,B1200,B300,B38400,B19200,B9600,B4800,B2400,B1200,B300,};
intname_arr[]={38400,19200,9600,4800,2400,1200,300,38400,19200,9600,4800,2400,1200,300,};
voidset_speed(intfd,intspeed){
inti;
intstatus;
structtermiosOpt;
tcgetattr(fd,&Opt);
for(i=0;i<sizeof(speed_arr)/sizeof(int);i++){
if(speed==name_arr[i]){
tcflush(fd,TCIOFLUSH);
cfsetispeed(&Opt,speed_arr[i]);
cfsetospeed(&Opt,speed_arr[i]);
status=tcsetattr(fd,TCSANOW,&Opt);
if(status!=0){
perror("tcsetattrfd1");
return;
}
tcflush(fd,TCIOFLUSH);
}
}
}
intset_Parity(intfd,intdatabits,intstopbits,intparity)
{
structtermiosoptions;
if(tcgetattr(fd,&options)!=0){
("SetupSerial1");
return(FALSE);
}
options.c_cflag&=~CSIZE;
switch(databits)
{
case7:
options.c_cflag|=CS7;
break;
case8:
options.c_cflag|=CS8;
break;
default:
fprintf(stderr,"Unsupporteddatasize ");return(FALSE);
}
switch(parity)
{
case'n':
case'N':
options.c_cflag&=~PARENB;/*Clearparityenable*/
options.c_iflag&=~INPCK;/*Enableparitychecking*/
break;
case'o':
case'O':
options.c_cflag|=(PARODD|PARENB);
options.c_iflag|=INPCK;/*Disnableparitychecking*/
break;
case'e':
case'E':
options.c_cflag|=PARENB;/*Enableparity*/
options.c_cflag&=~PARODD;
options.c_iflag|=INPCK;/*Disnableparitychecking*/
break;
case'S':
case's':/*asnoparity*/
options.c_cflag&=~PARENB;
options.c_cflag&=~CSTOPB;break;
default:
fprintf(stderr,"Unsupportedparity ");
return(FALSE);
}
switch(stopbits)
{
case1:
options.c_cflag&=~CSTOPB;
break;
case2:
options.c_cflag|=CSTOPB;
break;
default:
fprintf(stderr,"Unsupportedstopbits ");
return(FALSE);
}
/*Setinputparityoption*/
if(parity!='n')
options.c_iflag|=INPCK;
tcflush(fd,TCIFLUSH);
options.c_cc[VTIME]=150;
options.c_cc[VMIN]=0;/*UpdatetheoptionsanddoitNOW*/
if(tcsetattr(fd,TCSANOW,&options)!=0)
{
perror("SetupSerial3");
return(FALSE);
}
return(TRUE);
}
intmain()
{
printf("Thisprogramupdateslasttimeat%s%s ",__TIME__,__DATE__);
printf("STDIOCOM1 ");
intfd;
fd=open("/dev/ttyS0",O_RDWR);
if(fd==-1)
{
perror("serialporterror ");
}
else
{
printf("open");
printf("%s",ttyname(fd));
printf("succesfully ");
}
set_speed(fd,115200);
if(set_Parity(fd,8,1,'N')==FALSE){
printf("SetParityError ");
exit(0);
}
charbuf[]="fe55aa07bc010203040506073d";
write(fd,&buf,26);
charbuff[512];
intnread;
while(1)
{
if((nread=read(fd,buff,512))>0)
{
printf(" Len:%d ",nread);
buff[nread+1]='