Unix下socket编程常用系统调用函数:Server端

1. linux Socket(2) 函数

socket()函数创建了一个通信节点,并且返回一个指向这个阶段的文件描述符fd。调用的方法如下

#include           /* See NOTES */
#include 

int socket(int domain, int type, int protocol);

参数的描述

  1. domain用来选择通信协议,参数主要有一下一些常用类型
  • AF_UNIX, AF_LOCAL:用于本地通信,Unix Domain Socket
  • AF_INET:IPv4协议栈
  • AF_INET6:IPv6协议栈
  • 还有其他一些参看官方文档
  1. type参数定义通信语义
  • SOCK_STREAM:提供一种有序的,可靠的,双向的,基于连接的字节流
  • SOCK_DGRAM:支持数据报文(非连接的,不可靠的具有固定的最大字节长度的消息)
  • SOCK_SEQPACKET:提供一种有序的,可靠的,双向的基于连接的数据传输通道传输数据报文,报文的最大大小固定

在Linux 2.6.27版本以后,type参数可以按位添加新的属性(比如说使用'或'操作),支持新的一些特性

  • SOCK_NONBLOCK : 给新打开的文件描述符设置O_NONBLOCK文件状态标识
  • SOCK_CLOEXEC :给新打开的文件描述符设置FD_CLOEXEC标识(执行后关闭)
  1. protocol参数指定和socket一起使用的特殊的协议栈(比如说SCTP),

SOCK_STREAM类型的socket是一个全双工的字节流,不预留消息边界:

  • 一个stream socket必须处于连接状态才能收发数据;
  • 通过调用connect()函数来连接到另一个创建的socket;
  • 一旦连接建立起来了,就可以通过read()write()函数调用来进行数据传输了;
  • 最后调用close()函数关闭连接;
  • 实现了SOCK_STREAM的通信协议栈确保数据不会丢失或者重复;

SOCK_SEQPACKET使用的系统调用和SOCK_STREAM类型的socket一样,唯一的差异是read(2)函数只会返回请求的大小的数据包,多余的接收数据会被丢弃。同时会预留报文的消息边界

2. Linux bind(2)函数

bind()函数调用方法如下

#include 
#include 
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数的描述

通过socket()函数创建完socket以后,这时候socket还是只是属于某一个命名空间(地址族),并没有分配任何的地址。bind()函数通过addr参数来指定了socket的一个地址,sockfd参数是指向这个socket的文件描述符,addrlen指定了地址结构体的字节数。通常我们把这种操作称为是给socket命名。
地址结构体的定义取决于所用的通信协议族,比如说unix domian socket的通信方式AF_UNIX,它的地址结构定义如下:

struct sockaddr_un {
    sa_family_t sun_family;               /* AF_UNIX */
    char        sun_path[108];            /* pathname */
};

而如果socket创建的时候指定的通信协议是IP,比如说AF_INET对应的是IPV4,它的地址结构应该是由IP和Port来组成

struct sockaddr_in {
    sa_family_t    sin_family; /* address family: AF_INET */
    in_port_t      sin_port;   /* port in network byte order */
    struct in_addr sin_addr;   /* internet address */
};

原始的IP协议栈并没有port的概念,只有更高层的传输层协议比如说TCP,UDP才会有port的概念。

3. Linux listen(2)函数

函数的定义如下

#include           /* See NOTES */
#include 

int listen(int sockfd, int backlog);

参数的描述

listen()函数把socket标志成一个被动的socket,这个socket可以用于接收新的连接请求。

  • sockfd指向一个socket,socket的类型是SOCK_STREAM或者SOCK_SEQPACKET
  • backlog参数定义socket的等待连接的queue的最大长度。

4. Linux accept(2)函数

函数的定义如下

#include 
#include 

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

参数的描述

系统调用accept()函数用于基于连接的socket(比如说SOCK_STREAMSOCK_SEQPACKET)。

  1. sockfd是指向要处理的socket的文件描述符。
  • 这个socket首先通过socket(2)函数创建;
  • 然后通过bind(2)函数绑定到一个本地地址;
  • 最后通过函数调用listen(2)处于监听状态;
  • 系统调用accept(2)从socket的等待连接的queue里面取出第一个连接请求,然后创建一个处于连接状态的新的socket,并返回这个socket的文件描述符。新的socket不处于监听状态,老的socket不受影响
  1. addr是指向一个sockaddr结构体的指针,这个结构体里面填写的是对端socket的地址。
  2. addrlen代表地址结构的大小

如果queue里面没有等待的连接请求,并且socket没有标志成nonblocking,accept函数会阻塞等待新的请求;
如果socket标志成了nonblocking,并且queue里面没有等待的请求,accept函数会返回失败。

如果你希望监听socket上的连接请求,并且得到通知,可以使用slelect(2)poll(2)epoll(2)等函数。这个时候再去调用accept()函数来获取连接状态的socket

5. Linux connect(2)函数

函数定义

#include           /* See NOTES */
#include 

int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);

参数的描述

系统调用connect()发起一个当前socket到远端地址的一个连接,sockfd指定要发起连接的socket;addr指定连接的目标地址;addrlen指定地址结构体大小。

  • 如果socket的类型是SOCK_DGRAMaddr的地址就是数据报文发送的默认目的地址,并且是数据报文接收的唯一源地址;
  • 如果socket的类型是SOCK_STREAM或者SOCK_SEQPACKET,那么这个系统调用则会建立起一个连接,addr指定绑定的目的地址;

总的来说,基于连接的协议栈可以成功连接一次;非基于连接的协议栈可以连接多次来改变连接联合(association)。

6. Linux poll(2)函数

函数定义

#include 

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

参数的描述

poll()函数等待一组文件描述符准备好进行I/O操作。

  1. fds参数指定这一组文件描述符,实际上就是一个结构体数组,
struct pollfd{
  int fd;        /*file descriptor*/
  short events;    /* requested events*/
  short revents;    /* returned events */
};
  • fd代表一个文件描述符,比如说指向一个socket,或者指向一个打开的文件;
  • events是个bit mask,是一个输入参数,指定当前这个文件描述符期望的操作;
  • revents也是一个bitmask,是一个输出参数,内核会填写这个字段并返回,告诉application监听到的事件;
  1. nfds参数代表这个结构体数组元素的个数

  2. timeout设定超时长度,单位是毫秒(ms),这个函数调用会阻塞等待,直到出现以下场景:

  • 有一个文件描述符可以进行I/O操作了
  • 被信号量处理打断
  • 超时

返回值

poll函数可能有以下几种返回值

  • 正数,成功的时候返回一个正值,代表revents非零的结构体的个数;
  • 0,超时了,并且没有任何一个文件描述符ready;
  • -1,发生错误

7. Linux select(2)函数

函数定义及包含的头文件

#include 

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); 

参数的描述

select()函数允许程序监听多个文件描述符,直到一个或者多个文件描述符准备好进行I/O操作。

[REF]
socket(2)

你可能感兴趣的:(Unix下socket编程常用系统调用函数:Server端)