日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

linux/unix编程手册-61_64

發(fā)布時(shí)間:2024/4/13 linux 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux/unix编程手册-61_64 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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ě)
#include<unistd.h> #include<errno.h>ssize_t readn(int fd, void *buffer, size_t n){ssize_t numRead;size_t totRead;char *buf;buf = buffer;for (totRead = 0; totRead < n;){numRead = read(fd, buf, n-totRead);if (numRead == 0)return totRead;if (numRead == -1){if(errno==EINTR)continue;elsereturn -1;}totRead += numRead;buf += numRead;}return totRead; }ssize_t writen(int fd, const void *buffer, size_t n){ssize_t numWritten;size_t totWritten;const char* buf;buf = buffer;for (totWritten = 0; totWritten < n){numWritten = write(fd, buf, n-totWritten);if (numWritten <= 0){if (numWritten == -1 && errno == EINTR)continue;elsereturn -1;}totWritten += numWritten;buf += numWritten;}return totWritten; }復(fù)制代碼

shutdown()系統(tǒng)調(diào)用

#include<sys/socket.h>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
#include<sys/socket.h>ssize_t recv(int sockfd, void *buffer, size_t length, int flags);ssize_t send(int sockfd, const void *buffer, size_t length, int flags); 復(fù)制代碼

flags的具體參數(shù)略,flags給對(duì)于socket的I/O,提供了read,write的拓展

sendfile的優(yōu)化

#include<sys/sendfile.h>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),
#include<sys/socket.h>int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen);int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen); // 0 success, -1 error 復(fù)制代碼

其他基于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ù)決定的

獲取和修改終端屬性

#include<termios.h>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ù)用

#include<sys/time.h> #include<sys/select.h>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ì)算
#include<poll.h>int poll(struct pollfd fds[], nfds_t nfds, int timeout); //return ready fd 數(shù)量, 0 timeout, -1 error //select 將fd放在三個(gè)集合中,poll則在pollfd上標(biāo)明需要檢查的類(lèi)型struct pollfd{int fd;short events; //需要檢查的類(lèi)型掩碼short revents; //實(shí)際發(fā)生的類(lèi)型掩碼 }; // 掩碼常亮,略 復(fù)制代碼
  • 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

使用步驟

  • 設(shè)定信號(hào)處理例程,默認(rèn)情況下內(nèi)核發(fā)送的信號(hào)是SIGIO
  • 設(shè)定文件描述符的屬主,通常調(diào)用進(jìn)程會(huì)是屬主fcntl(fd, F_SETOWN, pid)
  • flags=fcntl(fd, F_GETFL)fcntl(fd, F_SETFL, flags | O_ASYNC | O_NONBLOCK) 復(fù)制代碼
  • 等待內(nèi)核的信號(hào)(邊緣觸發(fā)),盡可能多執(zhí)行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)型
    #include<sys/epoll.h>int epoll_create(int size); // return fd success ,-1 error // size 已經(jīng)被忽略了,之前是內(nèi)核為數(shù)據(jù)結(jié)構(gòu)劃分的初始大小int epoll_ctl(int epfd, int op, int fd, struct epoll_event *ev); // 0 s, -1 estruct epoll_event {uint32_t events; /* 感興趣事件集合*/epoll_data_t data; /* fd就緒時(shí),回傳的信息*/ };typedef union epoll_data {void *ptr; /* Pointer to user-defined data */int fd; /* File descriptor */uint32_t u32; /* 32-bit integer */uint64_t u64; /* 64-bit integer */ } epoll_data_t;int epoll_wait(int epfd, struct epoll_event *evlist, int maxevents, int timeout); // return ready fd 數(shù)量, 0 timeout, -1 error // timeout的處理poll 復(fù)制代碼

    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)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。