linux/unix编程手册-61_64
title: linux/unix編程手冊(cè)-61_64 date: 2018-10-07 11:53:07 categories: programming tags: tips
linux/unix編程手冊(cè)-61(SOCKET 高級(jí)特性)
流套接字上的部分讀和部分寫(xiě)
- 如果沒(méi)有足夠的緩沖區(qū)來(lái)傳輸所有字節(jié)并且滿足以下任意一個(gè)(關(guān)于write的fd不是普通文件時(shí)的原子性可以再搜搜)
- write()調(diào)用之后被信號(hào)中斷(一次write,buf小于緩沖區(qū)的大小,是原子性的操作?)
- 套接字工作在非阻塞模式下。可能當(dāng)前只傳輸了一部分請(qǐng)求字節(jié)(非阻塞模式下緩沖區(qū)不足只寫(xiě)入部分?)
- 部分字節(jié)傳輸完成后出現(xiàn)了異步錯(cuò)誤,比如TCP鏈接出現(xiàn)問(wèn)題
- readn和writen的實(shí)現(xiàn),避免部分讀寫(xiě)
shutdown()系統(tǒng)調(diào)用
int shutdown(int sockfd, int how); 復(fù)制代碼socket上調(diào)用close會(huì)關(guān)閉雙向兩端,shutdown會(huì)調(diào)節(jié),可使一個(gè)方向上進(jìn)行套接字傳輸,通過(guò)how
- SHUT_RD:關(guān)閉讀端,之后的讀操作返回文件EOF,但數(shù)據(jù)可以寫(xiě)入;在UNIX域流套接字執(zhí)行SHUT_RD,對(duì)端進(jìn)程會(huì)受到SIGPIPE
- SHUT_WR:關(guān)閉寫(xiě)端,后續(xù)本地的寫(xiě)操作會(huì)產(chǎn)生SIGPIPE信號(hào)和EPIPE錯(cuò)誤,對(duì)端寫(xiě)入可以在套接字上讀取,ssh連接會(huì)用到
- SHUT_RDWR:shutdown會(huì)關(guān)閉套接字通道無(wú)論套接字是否關(guān)聯(lián)其它文件描述符,是針對(duì)打開(kāi)文件來(lái)的,而close是針對(duì)文件描述符,需要所有socket的fd都關(guān)閉才會(huì)斷開(kāi)
- 后兩個(gè)TCP會(huì)主動(dòng)關(guān)閉,避免對(duì)TCP使用SHUT_RD
flags的具體參數(shù)略,flags給對(duì)于socket的I/O,提供了read,write的拓展
sendfile的優(yōu)化
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count); // 返回實(shí)際傳輸?shù)淖止?jié)數(shù),-1 error 復(fù)制代碼- out_fd通常指向套接字
- in_fd文件必須是可以mmap的,套接字不行
linux的TCP sendfile()的優(yōu)化 (例如http請(qǐng)求,首部信息胡通過(guò)write,頁(yè)面數(shù)據(jù)可以sendfile,導(dǎo)致TCP傳輸2個(gè)報(bào)文,網(wǎng)絡(luò)帶寬利用率低)
- linux TCP_CORK選項(xiàng),
其他基于TCP的一些略
一些常用的命令
- netstat:顯示系統(tǒng)中Internet和UNIX域套接字狀態(tài)
- tcpdump:
其他高級(jí)功能(當(dāng)手冊(cè)查吧)
linux/unix編程手冊(cè)-62(終端(串行終端,鍵盤(pán),顯示器之類(lèi)的))
終端驅(qū)動(dòng)程序
- 規(guī)范模式:終端輸入按行處理,且打開(kāi)了行編輯功能(可以刪除行等等之類(lèi))
- 非規(guī)范模式:終端輸入不會(huì)被裝配成行 ,禁用了行編輯,讀操作的完成時(shí)間等也是由c_cc數(shù)組中的位或其他參數(shù)決定的
獲取和修改終端屬性
struct termios {tcflag_t c_iflag; /* Input flags */tcflag_t c_oflag; /* Output flags */tcflag_t c_cflag; /* Control flags */tcflag_t c_lflag; /* Local modes */cc_t c_line; /* Line discipline (nonstandard)*/cc_t c_cc[NCCS]; /* Terminal special characters */speed_t c_ispeed; /* Input speed (nonstandard; unused) */speed_t c_ospeed; /* Output speed (nonstandard; unused) */ };int tcgetattr(int fd, struct termios *termios_p);int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);// 0 s, -1 e // fd必須是指向終端的描述符 復(fù)制代碼具體略,各種flag略
stty
stty -a
略(偏了)
使用命令tty,表示當(dāng)前終端對(duì)應(yīng)的設(shè)備文件,(以下#表示數(shù)字)
- 結(jié)果顯示:/dev/pts/# 表示偽終端
- 結(jié)果顯示:/dev/tty# 表示虛擬終端
- 結(jié)果顯示:/dev/console 表示物理終端(控制臺(tái))
- 結(jié)果顯示:/dev/ttys# 表示串行終端
linux/unix編程手冊(cè)-63(其他被選I/O模型)
傳統(tǒng)的read,write,沒(méi)有設(shè)置O_NONBLOCK時(shí),會(huì)以阻塞模式打開(kāi)文件,無(wú)法處理以下需求
- 以非阻塞檢查文件描述符是否可執(zhí)行I/O操作
- 同時(shí)檢查多個(gè)文件描述符看看能不能執(zhí)行I/O操作
之前不好的處理方案
- 非阻塞I/O盲輪訓(xùn)
- 多進(jìn)程或多線程
好的解決方案,這些技術(shù)不會(huì)實(shí)際執(zhí)行I/O只是告訴我們某個(gè)文件描述符就緒了,等準(zhǔn)備好了才會(huì)進(jìn)行I/O調(diào)用。
- I/O多路復(fù)用(select(), poll())
- 可移植性好
- 延展性差,fd多時(shí)效率低
- 信號(hào)驅(qū)動(dòng)I/O(和異步I/O的區(qū)別是,內(nèi)核通知信號(hào)后,會(huì)等待數(shù)據(jù)從內(nèi)核態(tài)傳到用戶態(tài),異步I/O不會(huì)等待內(nèi)核傳輸過(guò)程,因?yàn)闀?huì)將數(shù)據(jù)準(zhǔn)備好復(fù)制到用戶空間之后才會(huì)通知,看看posix的aio,go的話是基于CSP模型 CSP和Actors)
- 完全利用信號(hào)I/O的特點(diǎn)需要用到不可移植的linux的專(zhuān)有特性,移植性不好
- 可以高效大量fd
- linux epoll api(也屬于I/O多路復(fù)用)
- 專(zhuān)屬linux
- 和信號(hào)驅(qū)動(dòng)I/O比較
- 避免了處理信號(hào)復(fù)雜性
- 指定檢查類(lèi)型(讀就緒還是寫(xiě)就緒)
- 可以選擇水平觸發(fā)或者邊緣觸發(fā)
插一個(gè)
libevent 提供了I/O事件的抽象(不包含異步I/O?)水平觸發(fā)/邊緣觸發(fā)
- 水平觸發(fā)通知:如果文件描述符可以非阻塞的執(zhí)行I/O系統(tǒng)調(diào)用,認(rèn)為它準(zhǔn)備就緒
- 水平觸發(fā)允許我們重復(fù)檢測(cè)文件描述符的就緒狀態(tài),因此沒(méi)有必要每次觸發(fā)后盡可能多的執(zhí)行I/O會(huì)導(dǎo)致其他文件描述符饑餓狀態(tài)
- 邊緣觸發(fā)通知:如果文件描述符自上次狀態(tài)檢測(cè)以來(lái)有了新的活動(dòng)(I/O),需要觸發(fā)通知
- 只有I/O事件發(fā)生時(shí)我們才會(huì)收到通知,應(yīng)當(dāng)在收到通知后盡可能多的執(zhí)行I/O,不然的話下次輪訓(xùn)雖可用但不會(huì)通知,同時(shí)文件描述符通常應(yīng)當(dāng)設(shè)置成非阻塞。
備選I/O模型應(yīng)當(dāng)需要和O_NONBLOCK標(biāo)志一起使用
I/O多路復(fù)用
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); //return ready fd 數(shù)量, 0 timeout, -1 error // fdset最大1024,即FD_SETSIZE //select返回后,fdset只包含就緒的fdvoid FD_ZERO(fd_set *fdset); //置空 void FD_SET(int fd, fd_set *fdset); //加 void FD_CLR(int fd, fd_set *fdset); //刪 int FD_ISSET(int fd, fd_set *fdset); // 1在,否則不在 復(fù)制代碼- readfds:輸入是否就緒的文件描述符集合
- writefds:輸出。。。
- exceptfds:一些特殊情況的文件描述符集合
- 流式套接字上收到了帶外數(shù)據(jù)
- 連接到信包模式下的偽終端主設(shè)備上的從設(shè)備狀態(tài)發(fā)生了改變
- nfds需要比三個(gè)fdset最大文件描述符大1。提高select效率(select返回之后,可以根據(jù)0-nfds來(lái)遍歷)
- timeout
- 兩個(gè)域都為0則不會(huì)阻塞(沒(méi)有情況吧)
- NULL或timeout不為0會(huì)阻塞置
- fdset至少一個(gè)就緒
- 被信號(hào)終端
- 超時(shí)
- 返回值為正數(shù)時(shí),如果同一fd在對(duì)個(gè)set中都存在,都就緒了,會(huì)被重復(fù)計(jì)算
- timeout:
- -1,一直阻塞直到有ready的
- 0,不會(huì)阻塞
- 大于0,阻塞毫秒數(shù)
不同fd,select和poll的表現(xiàn)(可參考5.9,相關(guān)內(nèi)容是基礎(chǔ))
- 普通文件(因?yàn)閞ead,write不會(huì)阻塞)
- 總會(huì)被select標(biāo)記為可讀,可寫(xiě),poll后再revents中返回POLLIN,POLLOUT
- 終端和偽終端
- 管道和FIFO
- 套接字
select 和 epoll對(duì)比
- 實(shí)現(xiàn)都使用了內(nèi)核poll例程集合(不同于poll系統(tǒng)調(diào)用,具體以后查一下)
- poll是為每個(gè)fd調(diào)用內(nèi)核poll例程
- select 通過(guò)宏將例程信息轉(zhuǎn)化為select事件
- 性能
- fd范圍小或者密集時(shí)效率差不多
- fd稀疏時(shí)poll性能會(huì)好很多(不需要遍歷0~nfd)
- api(略)
select和poll的問(wèn)題
- 每次調(diào)用內(nèi)核必須檢查所有被指定的fd
- 每次調(diào)用需要傳遞一個(gè)表示所有被檢查文件fd的數(shù)據(jù)結(jié)構(gòu)到內(nèi)核(select還每次都要初始化這個(gè)數(shù)組)
- 每次返回。需要檢查數(shù)據(jù)結(jié)構(gòu)中的每個(gè)元素
- select和poll的調(diào)用結(jié)果內(nèi)核不會(huì)緩存
信號(hào)驅(qū)動(dòng)I/O
使用步驟
信號(hào)驅(qū)動(dòng)I/O 可應(yīng)用在套接字,終端/偽終端及其他設(shè)備,管道/FIFO, inotify文件描述符
曾今信號(hào)驅(qū)動(dòng)I/O也叫異步I/O,現(xiàn)在異步I/O特指, POSIX AIO規(guī)范提供的功能,POSIX AIO 進(jìn)程會(huì)請(qǐng)求內(nèi)核執(zhí)行一次I/O操作,當(dāng)I/O完成或出錯(cuò)之后,進(jìn)程會(huì)得到內(nèi)核的通知
不同fd觸發(fā)I/O就緒的信號(hào)的條件(略)
優(yōu)化信號(hào)驅(qū)動(dòng)I/O的使用
- 在同時(shí)檢查大量fd時(shí),信號(hào)驅(qū)動(dòng)I/O的優(yōu)勢(shì)在于,內(nèi)核會(huì)記住要檢查的文件描述符(O_ASYNC),僅當(dāng)I/O事件實(shí)際發(fā)生時(shí),才會(huì)發(fā)生信號(hào)
- 可以通過(guò)使用實(shí)時(shí)信號(hào)取代SIGIO來(lái)優(yōu)化性能
- 因?yàn)镾IGIO不會(huì)排隊(duì),處理了第一個(gè),后續(xù)的通知會(huì)丟失
- 如果信號(hào)處理例程是通過(guò)sigaction來(lái)安裝,可以通過(guò)sa.sa_flags指定SA_SIGINFO,傳遞是哪個(gè)fd,發(fā)生了何種事件
- 具體略
epoll 編程接口
- 性能上和信號(hào)驅(qū)動(dòng)I/O相似but
- 避免復(fù)雜的信號(hào)處理流程(ex:信號(hào)隊(duì)列溢出)
- 可以指定檢查類(lèi)型
epoll_create()
- 內(nèi)核會(huì)在內(nèi)存中創(chuàng)建一個(gè)新的i-node,并打開(kāi)文件描述符
epoll_ctl()
- fd 不能是普通文件,否則會(huì)EPERM, fd可以是epoll fd ,建立層次關(guān)系
- op
- EPOLL_CTL_ADD:fd已存在會(huì)EEXIST
- EPOLL_CTL_MOD:通過(guò)ev修改fd上的設(shè)定事件,fd需要已經(jīng)在列表中,否則ENOENT
- EPOLL_CTL_DEL:fd 不存在會(huì)ENOENT
- 多線程中一個(gè)線程,epoll_ctl修改了列表,另一個(gè)線程epoll_wait()的列表會(huì)同步,會(huì)立刻更新
epoll_wait()
- maxevents應(yīng)該只是如果超過(guò),只會(huì)返回這么多,沒(méi)有等待這么多才返回的語(yǔ)義
- EPOLLONESHOT, fd就緒一次之后,會(huì)將fd置為非激活狀態(tài),若重新監(jiān)控需要epoll_ctl重設(shè)
- 使用dup()類(lèi)似函數(shù)復(fù)制一個(gè)epoll_fd時(shí),或fork()時(shí),新的epoll_fd指向同一epoll數(shù)據(jù)結(jié)構(gòu)(中文版翻譯錯(cuò)了)
- 監(jiān)控和的fd映射的打開(kāi)文件描述(第二層)關(guān)聯(lián)的所有fd都關(guān)閉后,epoll會(huì)自動(dòng)把它從監(jiān)控列表刪除
epoll和I/O多路復(fù)用的對(duì)比
- 每次調(diào)用poll/select,內(nèi)核會(huì)檢查所有指定的文件描述符,每次調(diào)用都會(huì)和內(nèi)核傳遞一次文件描述符的數(shù)據(jù)結(jié)構(gòu);
- epoll在epoll_ctl指定監(jiān)控fd時(shí),內(nèi)核會(huì)在打開(kāi)文件描述上下文想關(guān)聯(lián)列表記錄這個(gè)fd,每當(dāng)一個(gè)fd就緒時(shí),會(huì)在epoll_fd的就序列表添加一個(gè)元素(一個(gè)文件的I/O會(huì)使所有關(guān)聯(lián)fd就緒),每次調(diào)用epoll_wait()不需要從用戶空間傳數(shù)據(jù)到內(nèi)核空間,只有內(nèi)核返回。
- epoll默認(rèn)是水平觸發(fā),和select/epoll類(lèi)似
- epoll設(shè)置邊緣觸發(fā)之后,一次epoll_wait時(shí),一個(gè)fd有多個(gè)I/O事件,會(huì)合并成一次單獨(dú)的通知(信號(hào)驅(qū)動(dòng)會(huì)是多個(gè))
- 優(yōu)化,記錄下每個(gè)就緒fd,不要一次讀完一個(gè)fd,設(shè)定一個(gè)限度。(水平的話與需要做限度,但是不用記錄)
linux/unix編程手冊(cè)-64(SOCKET 偽終端)
偽終端程序通過(guò)IPC,連接終端程序
偽終端程序流程(server 端,例如ssh)
- 驅(qū)動(dòng)程序打開(kāi)偽終端主設(shè)備(sshd)
- fork()一個(gè)子進(jìn)程
- 調(diào)用setsid()改變會(huì)話id,創(chuàng)建一個(gè)新會(huì)話,子進(jìn)程會(huì)成為新會(huì)話的首進(jìn)程
- 打開(kāi)從設(shè)備,子進(jìn)程成為從設(shè)備的控制進(jìn)程
- 用dup()類(lèi)系統(tǒng)調(diào)用復(fù)制標(biāo)準(zhǔn)的fd,0,1,2
- 調(diào)用exec()啟動(dòng)連接到偽終端從設(shè)備的面向終端程序(shell)
偽終端的系統(tǒng)調(diào)用(略)
偽終端I/O(類(lèi)似雙向管道,不同fd關(guān)閉的異常,信包模式)(略)
END
總結(jié)
以上是生活随笔為你收集整理的linux/unix编程手册-61_64的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Java获得时间 String与Time
- 下一篇: linux 其他常用命令