linux网络编程之网络函数详解

一、epoll_create函数
  函数声明:int epoll_create(int size)
  该 函数生成一个epoll专用的文件描述符。它实际上是在内核申请一空间,用来存放你想关注的socket fd上是否发生以及发生了什么事件。size就是你在这个epoll fd上能关注的最大socket fd数。随你定好了,前提是有足够的空间。
linux

2. socket 函数
程序员

  函数原型 int socket(int domain, int type, int protocol);
  应用程序调用socket函数来建立一个可以进行网络通讯的套接字,即套接口描述文件字,它是一个整数,如同文件描述符同样,是内核一个I/O结构的索引。经过socket函数,咱们指定一个套接口的协议相关的属性, 为进行使用socket api作好准备。
   第一个参数指定一个协议簇,也每每被称为协议域。系统存在许多能够的协议簇,常见有AF_INET──指定为IPv4协议,AF_INET6──指定为 IPv6,AF_LOCAL──指定为UNIX 协议域等等。它值都是系统预先定义的宏,系统支持哪些协议咱们才可使用,不然会调用失败。协议簇是网络层的协议。
   第二个参数指定一个套接口的类型,套接口可能的类型有:SOCK_STREAM、SOCK_DGRAM、SOCK_SEQPACKET、SOCK_RAW等等,它们 分别代表字节流、数据报、有序分组、原始套接口。这其实是指定内核为咱们提供的服务抽象,好比咱们要一个字节流。须要注意的,并非每一种协议簇都支持 这里的全部的类型,因此类型与协议簇要匹配。;
  第三个参数指定应用程序所使用的传输协议,也就是诸如TCP或UDP协议等等,系统针对每个协议簇与类型提供了一个默认的协议,一般咱们经过把protocol设置为0来使用这 个默认的值。注意这里的协议与上面的协议簇是两个不一样的概念,前者是指网络层的协议,因为它对于到传输层会出现许多协议,好比IPv4能够用来实现TCP 或UDP等等传输层协议,因此称为协议簇。相应的传输层的协议就简单地称为协议。常见的协议有TCP、UDP、SCTP,要指定它们分别使用宏 IPPROTO_TCP、IPPROTO_UPD、IPPROTO_SCTP来指定。

api

  该函数若是调用成功就返回新建立的套接字的描述符,若是失败就返回 INVALID_SOCKET。套接字描述符是一个整数类型的值。每一个进程的进程空间里都有一个套接字描述符表,该表中存放着套接字描述符和套接字数据结 构的对应关系。该表中有一个字段存放新建立的套接字的描述符,另外一个字段存放套接字数据结构的地址,所以根据套接字描述符就能够找到其对应的套接字数据结构。每一个进程在本身的进程空间里都有一个套接字描述符表可是套接字数据结构都是在操做系统的内核缓冲里。数组

3.  fcntl函数服务器

  函数原型:网络

  #include <unistd.h>
  #include <fcntl.h>
  int fcntl(int fd, int cmd);
  int fcntl(int fd, int cmd, long arg);
  int fcntl(int fd, int cmd, struct flock *lock);
数据结构

  功能:改变一个已打开的文件的属性,能够从新设置读、写、追加、非阻塞等标志(这些标志称为File并发

  这个函数和open 同样,也是用可变参数实现的,可变参数的类型和个数取决于前面的cmd 参数。dom

  针对第2个参数,int cmd异步

  fcntl函数有五种功能:
  • 复制一个现存的描述符(cmd=F_DUPFD)    。
  • 得到/设置文件描述符标记(cmd=F_GETFD或F_SETFD)   。
  • 得到/设置文件状态标志(cmd=F_GETFL或F_SETFL) 。
  • 得到/设置异步I/O有权(cmd=F_GETOWN或F_SETOWN) 。
  • 得到/设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW)。

  将涉及与进程表项中各文件描述符相关联的文件描述符标志, 以及每一个文件表项中的文件状态标志,

  一~复制文件描述符
  • F_DUPFD 复制文件描述符filedes,新文件描述符做为函数值返回。它是还没有打开的各
  描述符中大于或等于第三个参数值(取为整型值)中各值的最小值。新描述符与 filedes 共享同
  一文件表项。可是,新描述符有它本身的一套文件描述符标志,其 F D _ C L O E X E C
  文件描述符标志则被清除。
  • F_GETFD 对应于filedes 的文件描述符标志做为函数值返回。当前只定义了一个文件描
  述符标志FD_CLOEXEC。
  • F_SETFD 对于filedes 设置文件描述符标志。新标志值按第三个参数 (取为整型值)设置。
  应当了解不少现存的涉及文件描述符标志的程序并不使用常数 F D _ C L O E X E C,而是将此
  标志设置为0(系统默认,在exec时不关闭)或1(在exec时关闭)。

  二~文件描述符号,套接口 属性相关
  • F_GETFL 对应于filedes 的文件状态标志做为函数值返回。在说明 open函数时,已说明
  了文件状态标志   不幸的是,三个存取方式标志 (O_RDONLY,O_WRONLY,以及O_RDWR)并不各占1位。(正
  如前述,这三种标志的值各是 0、1和2,因为历史缘由。这三种值互斥 — 一个文件只能有这
  三种值之一。 )所以首先必须用屏蔽字 O_ACCMODE相与 取得存取方式位,而后将结果与这三种值
  相比较。
  • F_SETFL 将文件状态标志设置为第三个参数的值 (取为整型值)。 能够更改的几个标志是:
  O_APPEND,O_NONBLOCK,O_SYNC和O_ASYNC。

  fcntl的文件状态标志共有7个,O_RDONLY,O_WRONLY,O_RDWR,O_APPEND,O_NONBLOCK,O_SYNC和O_ASYNC


  三~信号驱动I/O , 带外数据,设置套接口接受信号的属主
  SIGIO,跟信号驱动I/O有关
  SIGURG, 和接受带外数据有关
  • F_GETOWN 取当前接收SIGIO和SIGURG信号的进程ID或进程组ID。12.6.2节将论述这
  两种4.3+BSD异步I/O信号。
  • F_SETOWN 设置接收SIGIO和SIGURG信号的进程ID或进程组ID。正的arg指定一个进
  程ID,负的arg表示等于arg绝对值的一个进程组ID

三、epoll_ctl函数
     函数声明:int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
    
该函数用于控制某个文件描述符上的事件,能够注册事件,修改事件,删除事件。
    参数:epfd:由 epoll_create 生成的epoll专用的文件描述符;
                op:要进行的操做例如注册事件,可能的取值EPOLL_CTL_ADD 注册、EPOLL_CTL_MOD
                        改、EPOLL_CTL_DEL 删除
                fd:关联的文件描述符;
                event:指向epoll_event的指针;
    若是调用成功返回0,不成功返回-1

四、epoll_wait函数
  函数声明:int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout)
  该函数用于轮询I/O事件的发生;
  参数:
  epfd:由epoll_create 生成的epoll专用的文件描述符;
  epoll_event:用于回传代处理事件的数组;
  maxevents:每次能处理的事件数;
  timeout:等待I/O事件发生的超时值;
    返回发生事件数。

介绍linux下的epoll(7)方法,其有着良好的就绪事件通知机制。咱们将会使用C来展示一个完整的TCP服务器实现代码。 Epoll是被linux2.6开始引进的,可是不被其余的类UNIX系统支持,它提供了一种相似select或poll函数的机制:

   1.Select(2)只可以同时管理FD_SETSIZE数目的文件描述符

 

       2. poll(2)没有固定的描述符上限这一限制,可是每次必须遍历全部的描述符来检查就绪的描述符,这个过程的时间复杂度为O(N)。

 

      epoll没有select这样对文件描述符上限的限制,也不会像poll那样进行线性的遍历。所以epoll处理大并发链接有着更高的性能。

 

    Epoll相关操做函数介绍:

 

     1. epoll_create(2) or epoll_create1(2)(有着不一样的参数值)用来建立epoll实例。

 

/usr/include/sys/epoll.h
extern int epoll_create (int __size) ;
RETURN:>0, 成功;-1, 出错

 

函数描述:

 

       (1) epoll_create返回的是一个文件描述符,也就是说epoll是以特殊文件的方式体现给用户

 

       (2) __size提示操做系统,用户可能要使用多少个文件描述符,该参数已经废弃,填写一个大于0的正整数

 

      2.  epoll_ctl(2)用来增长或移除被epoll所监听的文件描述符。

 

int epoll_ctl(int epfd, int op, int fd, struct 	epoll_event *event);
RETURN:0,成功;-1,出错

 

函数描述:

 

        (1) epfd为epoll_create建立的epoll描述符

 

        (2) epoll_ctl函数对epoll进行op类型的操做,op选项为

 

              EPOLL_CTL_ADD,对fd描述符注册event事件

 

              EPOLL_CTL_MOD,对fd描述符的event事件进行修改

 

              EPOLL_CTL_DEL,删除已注册的event事件

 

      3. epoll_wait(2)用来等待发生在监听描述符上的事件。它会一直阻塞直到事件发生。

 

#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event *events,
				int maxevents, int timeout);
RETURN:>0,发生事件个数;=0,时间到;-1,出错

 

函数描述:

 

           epoll_wait与select函数相似,同步地等待事件发生

 

           (1) epfd,标识epoll的文件描述符

 

           (2) events,指向传入操做系统的一个epoll_event数组

 

           (3) maxevents,表示传入数组的大小,必须大于0

 

          当有事件发生,Linux会填写events结构,返回给应用程序。因为epoll_wait同步等待,有可能被信号中断,返回EINTR错误

 

      更多的函数介绍请参照man。  

 

Epoll的两种模式:

 

      1. 水平触发(LT):使用此种模式,当数据可读的时候,epoll_wait()将会一直返回就绪事件。若是你没有处理彻底部数据,而且再次在该 epoll实例上调用epoll_wait()才监听描述符的时候,它将会再次返回就绪事件,由于有数据可读。ET只支持非阻塞socket。

 

      2. 边缘触发(ET):使用此种模式,只能获取一次就绪通知,若是没有处理彻底部数据,而且再次调用epoll_wait()的时候,它将会阻塞,由于就绪事件已经释放出来了。

 

ET的效能更高,可是对程序员的要求也更高。在ET模式下,咱们必须一次干净而完全地处理完全部事件。LT两种模式的socket都支持。

 

     传递给epoll_ctl(2)的Epoll事件结构体以下所示:

 

typedefunionepoll_data
{
void*ptr;
intfd;
  __uint32_t   u32;
  __uint64_t   u64;
}epoll_data_t;

structepoll_event
{
  __uint32_t   events;/* Epoll events */
epoll_data_t data;/* User data variable */
};

 

      对于每个监听的描述符,可以关联一个整形数据或指向用户数据的指针。

 

      epoll的事件类型:

 

enum EPOLL_EVENTS
  {
    EPOLLIN = 0x001,
#define EPOLLIN EPOLLIN
    EPOLLPRI = 0x002,
#define EPOLLPRI EPOLLPRI
    EPOLLOUT = 0x004,
#define EPOLLOUT EPOLLOUT
    EPOLLRDNORM = 0x040,
#define EPOLLRDNORM EPOLLRDNORM
    EPOLLRDBAND = 0x080,
#define EPOLLRDBAND EPOLLRDBAND
    EPOLLWRNORM = 0x100,
#define EPOLLWRNORM EPOLLWRNORM
    EPOLLWRBAND = 0x200,
#define EPOLLWRBAND EPOLLWRBAND
    EPOLLMSG = 0x400,
#define EPOLLMSG EPOLLMSG
    EPOLLERR = 0x008,
#define EPOLLERR EPOLLERR
    EPOLLHUP = 0x010,
#define EPOLLHUP EPOLLHUP
    EPOLLRDHUP = 0x2000,
#define EPOLLRDHUP EPOLLRDHUP
    EPOLLONESHOT = (1 << 30),
#define EPOLLONESHOT EPOLLONESHOT
    EPOLLET = (1 << 31)
#define EPOLLET EPOLLET
  };

 

– EPOLLIN,读事件

 

– EPOLLOUT,写事件

 

– EPOLLPRI,带外数据,与select的异常事件集合对应

 

– EPOLLRDHUP,TCP链接对端至少写写半关闭

 

– EPOLLERR,错误事件

 

– EPOLLET,设置事件为边沿触发

 

– EPOLLONESHOT,只触发一次,事件自动被删除

 

      epoll在一个文件描述符上只能有一个事件,在一个描述符上添加多个事件,会产生EEXIST的错误。一样,删除epoll的事件,只需描述符就够了

 

      epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);

 

      这里有一个比较重要的问题:从epoll_wait返回的events中,该如何知道是哪一个描述符上的事件:在注册epoll事件的时候,必定要填写epoll_data,不然咱们将分不清触发的是哪一个描述符上的事件。

相关文章
相关标签/搜索