linux io複用api參數


Linux select api

linux select api  4.14.0.rc4
https://www.kernel.org/doc/html/latest/media/uapi/v4l/func-select.html?highlight=select

select Synchronous I/O multiplexing

select系統調用原型
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)

Description:
使用select()函數,應用程序可以暫停執行,直到驅動程序捕獲數據或準備接受數據進行輸出。
當streaming I/O 已協商時,此功能等待直到緩衝區已被填充或顯示,並可以使用VIDIOC_DQBUF ioctl出隊。當緩衝區已經在驅動程序的傳出隊列中時,該函數立即返回。
On success select() returns the total number of bits set in struct fd_set(). When the function timed out it returns a value of zero. On failure it returns -1 and the errno variable is set appropriately. When the application did not call ioctl VIDIOC_QBUF, VIDIOC_DQBUF or ioctl VIDIOC_STREAMON, VIDIOC_STREAMOFF yet the select() function succeeds, setting the bit of the file descriptor in readfds or writefds, but subsequent VIDIOC_DQBUF calls will fail. [1]

當使用read()函數並且驅動程序尚未捕獲時,select()函數開始捕獲。當失敗時,select()返回成功,並且隨後的read()調用也將嘗試開始捕獲,將返回相應的錯誤代碼。當驅動程序連續捕獲(與例如靜止圖像相反)並且數據已經可用時,select()函數立即返回。

當使用write()函數已經協商時,select()函數只是等待直到驅動程序準備好進行非阻塞的write()調用。

實現read()或write()函數或流I / O的所有驅動程序也必須支持select()函數。

有關詳細信息,請參閱select()手冊頁。

[1] The Linux kernel implements select() like the poll() function, but select() cannot return a POLLERR.

Return Value:
EBADF
One or more of the file descriptor sets specified a file descriptor that is not open.
EBUSY
The driver does not support multiple read or write streams and the device is already in use.
EFAULT
The readfds, writefds, exceptfds or timeout pointer references an inaccessible memory area.
EINTR
The call was interrupted by a signal.
EINVAL
The nfds argument is less than zero or greater than FD_SETSIZE.


https://www.kernel.org/doc/html/latest/media/uapi/v4l/func-poll.html?highlight=poll
#include <sys/poll.h>
int poll(struct pollfd *ufds, unsigned int nfds, int timeout)






epoll 參數總結

https://www.cnblogs.com/luoxn28/p/6220372.html


1、基本知識
  epoll是在2.6內核中提出的,是之前的select和poll的增強版本。相對於select和poll來說,epoll更加靈活,沒有描述符限制。epoll使用一個文件描述符管理多個描述符,將用戶關係的文件描述符的事件存放到內核的一個事件表中,這樣在用戶空間和內核空間的copy只需一次。
2、epoll接口
  epoll操作過程需要三個接口,分別如下:
#include <sys/epoll.h>
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
(1) int epoll_create(int size);
  創建一個epoll的句柄,size用來告訴內核這個監聽的數目一共有多大。這個參數不同於select()中的第一個參數,給出最大監聽的fd+1的值。需要注意的是,當創建好epoll句柄後,它就是會佔用一個fd值,在linux下如果查看/proc/進程id/fd/,是能夠看到這個fd的,所以在使用完epoll後,必須調用close()關閉,否則可能導致fd被耗盡。
(2)int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
  epoll的事件註冊函數,它不同與select()是在監聽事件時告訴內核要監聽什麼類型的事件epoll的事件註冊函數,它不同與select()是在監聽事件時告訴內核要監聽什麼類型的事件,而是在這裏先註冊要監聽的事件類型。第一個參數是epoll_create()的返回值,第二個參數表示動作,用三個宏來表示:
EPOLL_CTL_ADD:註冊新的fd到epfd中;
EPOLL_CTL_MOD:修改已經註冊的fd的監聽事件;
EPOLL_CTL_DEL:從epfd中刪除一個fd;
第三個參數是需要監聽的fd,第四個參數是告訴內核需要監聽什麼事,struct epoll_event結構如下:
struct epoll_event {
__uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
events可以是以下幾個宏的集合:
EPOLLIN :表示對應的文件描述符可以讀(包括對端SOCKET正常關閉);
EPOLLOUT:表示對應的文件描述符可以寫;
EPOLLPRI:表示對應的文件描述符有緊急的數據可讀(這裏應該表示有帶外數據到來);
EPOLLERR:表示對應的文件描述符發生錯誤;
EPOLLHUP:表示對應的文件描述符被掛斷;
EPOLLET: 將EPOLL設爲邊緣觸發(Edge Triggered)模式,這是相對於水平觸發(Level Triggered)來說的。
EPOLLONESHOT:只監聽一次事件,當監聽完這次事件之後,如果還需要繼續監聽這個socket的話,需要再次把這個socket加入到EPOLL隊列裏
(3) int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
  等待事件的產生,類似於select()調用。參數events用來從內核得到事件的集合,maxevents告之內核這個events有多大,這個maxevents的值不能大於創建epoll_create()時的size,參數timeout是超時時間(毫秒,0會立即返回,-1將不確定,也有說法說是永久阻塞)。該函數返回需要處理的事件數目,如返回0表示已超時。
3、工作模式
  epoll對文件描述符的操作有兩種模式:LT(level trigger)和ET(edge trigger)。LT模式是默認模式,LT模式與ET模式的區別如下:
  LT模式:當epoll_wait檢測到描述符事件發生並將此事件通知應用程序,應用程序可以不立即處理該事件。下次調用epoll_wait時,會再次響應應用程序並通知此事件。
  ET模式:當epoll_wait檢測到描述符事件發生並將此事件通知應用程序,應用程序必須立即處理該事件。如果不處理,下次調用epoll_wait時,不會再次響應應用程序並通知此事件。
  ET模式在很大程度上減少了epoll事件被重複觸發的次數,因此效率要比LT模式高。epoll工作在ET模式的時候,必須使用非阻塞套接口,以避免由於一個文件句柄的阻塞讀/阻塞寫操作把處理多個文件描述符的任務餓死。


socket api 參數
一、套接字數據結構
1、通用套接字地址
struct   sockaddr 
{
sa_family_t   sa_family;   //通信類型,對於IPV4爲AF_INET
char   sa_data[14];   //用來保存IP地址和端口信息,一般不用
}

2、IPV4套接字地址
struct   sockaddr_in
{
unsigned   short   sin_len;//IPV4地址長度
sa_family_tsin_family;//通信類型
unsigned   short   int   sin_port;//端口號
struct   in_addr   sin_addr;//IP地址
unsigned   char   sin_zero[8];//補充字段
}
其中struct   in_addr爲:
struct   in_addr
{
uint32_t   s_addr;//32位IP地址,網絡字節順序

}

3、hostent
struct   hostent
{
char*    h_name;//主機的正式名
char**   h_aliases;//主機的別名
int   h_addrtype;//主機的地址類型,IPV4爲AF_INET
int   h_length;//地址長度,IPV4爲32
char**   h_addr_list;//主機的IP地址列表
}
#define   h_addr   h_addr_list[0]//主機的第一個IP地址

POSIX中的數據類型
數據類型說明頭文件
int8_t帶符號的8位整數<sys/types.h>
uint8_t無符號的8位整數<sys/types.h>
int16_t帶符號的16位整數<sys/types.h>
uint16_t無符號的16位整數<sys/types.h>
int32_t帶符號的32位整數<sys/types.h>
uint32_t無符號的32位整數<sys/types.h>
sa_family_t套接字地址結構的地址族<sys/socket.h>
socklen_t套接字地址結構的長度,一般爲uint32_t<sys/socket.h>
int_port_tTCP或者UDP端口號,一般爲uint16_t<netinet/in.h>
in_addr_tIPV4地址,一般爲uint32_t<netinet/in.h>

二、基礎函數

1、主機字節序和網絡字節序
#include<netinet/in.h>
uint32_t htonl(uint32_t   hostlong)
uint16_t   htons(uint16_t   hostsho以上rt)
以上兩個函數返回網絡字節序
     
        uint32_t   ntohl(uint32_t   netlong)
uint16_t   ntohs(uint16_t   netshort)
以上兩個函數返回主機字節序

2、字節操作函數
#include<string.h>
void   memset(void*   dest,int   c,size_t   len)
void   memcpy(void*   dest,const   void*   src,size_t   nbytes)
int   memcmp(const   void*   ptr1,const   void*   ptr2,size_t   nbytes)

3、整數與IP地址轉換
TCP/IP中的IP地址是以''.''隔開的十進制的數,而套接字中用的是32位的網絡字節序的二進制數值。

#include<arpa/inet.h>
int   inet_aton(const   char*   straddr,struct   in_addr*   addrptr)
若成功則返回1,否則返回0
參數:straddr爲點分十進制字符串,結果保存在addrptr所指的內存中


char*   inet_ntoa(struct   in_addr   inaddr)
若成功則返回點分十進制數串的指針,否則返回NULL
參數:inaddr爲32位網絡字節的整數,返回點分十進制數串的指針

in_addr_t   inet_addr(const   char*   straddr)
若成功則返回32位的二進制網絡字節序的地址,否則返回INADDR_NONE(表示一個不存在的IP地址,其實就是255.255.255.255,就是-1)
參數:straddr爲點分十進制字符串,返回爲32位的二進制網絡字節序的地址

4、域名與IP地址的轉換
#include<netdb.h>
struct   hostent*   gethostbyname(const   char*   hostname)
struct   hostent*   gethostbyaddr(const   char*   addr,size_t   len,int   family)
若成功返回hostent結構指針,否則返回空指針,同時設置h_errno,可以調用hstrerror()函數獲取h_errno的值

h_errno的取值:
HOST_NOT_FOUND找不到主機
TRY_AGAIN出錯重試
NO_RECOVERY不可修復性錯誤
NO_DATA指定的名字有效,但是沒有記錄

5、其他常用函數:
若IP地址設爲INADDR_ANY則表示本機IP,這時可以在瀏覽器中輸入
http://localhost:端口號/
作爲客戶端向服務器發出鏈接請求

一般出錯信息可以用perror來輸出
void   perror(const   char*   s)
該函數除了會輸出字符串s,還會輸出錯誤原因

三、TCP編程

頭文件:#include<sys/socket.h>
服務器流程:socket()→bind()→listen()→accept()→recv()<═>send()→close()
客戶端流程:socket()→connect()→send()<═>recv()→close()

1、創建套接字

int   socket(int   family,int   type,int   ptotocol)
若成功則返回套接字描述符,否則返回-1
參數:family取值:PF_INET(等價於AF_INET)、PF_INET6(等價於AF_INET6)
    (PF代表Protocl Family協議族,AF代表Address Family地址族)
    type取值:SOCK_STREAM、SOCK_DGRAM、SOCK_RAW
    ptotocol一般取0

2、綁定端口

int   bind(int   sockfd,const   struct   sockaddr*   my_addr,socklen_t   addrlen)
若成功返回0,否則返回-1
若出錯,則可以在errno中捕獲:
EBADF:參數sockfd不合法
EACCEDD:權限不足
ENOTSOCK:參數sockfd是一個文件描述符,而不是socket

3、等待監聽

int   listen(int   sockfd,int   backlog)
若成功則返回0,否則返回-1
參數:sockfd表示要監聽的套接字,backlog表示最多同時處理的請求數(若爲IPV4則最多爲128),若超過這個個數,則客戶端會受到ECONNREFUSED錯誤
若出錯,則可以在errno中捕獲:
EBADF:參數sockfd不合法
EACCEDD:權限不足
EOPNOTSUPP:指定的socket不支持listen

4、接受鏈接

int   accept(int   sockfd,struct   sockaddr*   addr,socketlen_t*   addrlen)
若成功則返回新的套接字,否則返回-1
參數:sockfd表示處於監聽的套接字,addr表示客戶端的信息
accept接受一個鏈接時會返回一個新的套接字,以後的數據傳輸就用這個新的套接字處理若出錯,則可以用errno捕獲:
EBADF:參數sockfd不合法
EFAULT:參數addr指針指向無法存取的空間
ENOTSOCK:參數sockfd是一個文件描述符,而不是socket
EOPNOTSUPP:制定的socket不是SOCK_STREAM
EPERM:防火牆拒絕這個鏈接
ENOBUFS:系統緩衝內存不足
ENOMEM:核心內存不足

5、請求鏈接

int   connect(int   sockfd,const   struct   sockaddr*   serv_addr,int   addrlen)
若成功返回0,否則返回-1
參數:sockfd表示已經建立好的套接字,serv_addr保存服務器信息
若出錯,可以在errno中捕獲:
EBADF:參數sockfd不合法
EFAULT:參數addr指針指向無法存取的空間
ENOTSOCK:參數sockfd是一個文件描述符,而不是socket
EISCONN:參數sockfd的套接字已經處於鏈接狀態
ECONNREFUSED:鏈接請求被拒絕
ETIMEDOUT:超時
ENETUNREACH:無法傳送數據包到指定主機
EAFNOSUPPORT:sockaddr結構的sa_family不正確
EALREADY:socket不能阻斷,但是以前的鏈接操作還未完成

6、數據發送和接收

int   send(int   sockfd,const   void*   buf,int   len,unsigned   int   flags)
int   recv(int   sockfd,void*   buf,int   len,unsigned   int   flags)
若成功則返回已經發送或者接收的字節數,否則返回-1
flags一般置0
若出錯,可以在errno中捕獲:
EBADF:參數sockfd不合法
EFAULT:參數addr指針指向無法存取的空間
ENOTSOCK:參數sockfd是一個文件描述符,而不是socket
EINTR:進程被信號中斷
EAGAIN:此動作會中斷進程,但參數sockfd的套接字不可中斷
ENOBUFS:系統的緩衝內存不足
ENOMEM:核心內存不足
EINVAL:函數參數不正確

7、write和read函數

#include<unistd.h>
ssize_t   write(int   fd,const   void*   buf,size_t   count)
ssize_t   read(int   fd,void*   buf,size_t   count)
若成功返回寫入和讀取的字節數,否則返回-1

注意:write等價於send,read等價於recv

8、關閉套接字

#include<unistd.h>
int   close(int   fd)
若成功返回0,否則返回-1






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章