18.3.6 接受连接
服务器上的应用程序创建好命名套接字之后,就可以通过accept()系统调用来等待客户端程序建立对该套接字的连接了。accept()的一般形式是:
int accept(int socket, struct sockaddr *address, size_t *address_len);
accept()系统调用会等到有客户程序试图连接到由socket参数指定的套接字时才返回。该客户就是套接字队列里排在第一位的连接。accept()函数将创建出一个新的套接字来与该客户进行通信,返回的是与之对应的文件描述符。新套接字的类型与服务器监听套接字的类型相同。
套接字必须是被bind()调用命名过的,并且还要有一个由listen()调用分配的连接队列。客户的地址将被放在address指向的sockaddr结构里。如果不关心客户的地址,可以在这里使用一个空指针。
参数address_len给出了客户结构的长度。如果客户地址的长度超过了这个值,就会被截短。在调用accept()之前,必须把address_len设置为预期的地址长度。当这个调用返回时,address_len将被设置为客户的地址结构的实际长度。
如果套接字队列里没有排队等候的连接,accept将阻塞程序,直到有客户建立连接为止。这个行为可以用O_NONBLOCK标志改变,方法是对这个套接字文件描述符调用fcntl()函数。代码如下:
int flags = fcntl(socket, F_GETFL, 0);
fcntl(socket, F_SETFL, O_NONBLOCK|flags);
如果有排队等候的客户连接,accept()函数将返回一个新的套接字文件描述符,否则它将返回–1。其错误原因除类似于bind()调用和listen()调用中的情况之外,还有一个EWOULDBLOCK,如果前面指定了O_NONBLOCK标志,但队列里没有排队的连接,就会出现这个错误。如果进程阻塞在accept()调用里的时候执行被中断了,就会出现EINTR错误。