既然服务端已经很虔诚了,很真诚了,处于倾听状态,那么该是去尝试接受客户端请求的时候了,别只顾着倾听,不去接纳别人。
接纳客户端请求的函数是accept, 我们先来看看函数的原型:
WINSOCK_API_LINKAGE
SOCKET
WSAAPI
accept(
SOCKET s,
struct sockaddr FAR * addr,
int FAR * addrlen
);
函数的第一个参数用来标识服务端套接字(也就是listen函数中设置为监听状态的套接字),第二个参数是用来保存客户端套接字对应的“地方”(包括客户端IP和端口信息等), 第三个参数是“地方”的占地大小。返回值对应客户端套接字标识。
实际上是这样的: accept函数指定服务端去接受客户端的连接,接收后,返回了客户端套接字的标识,且获得了客户端套接字的“地方”(包括客户端IP和端口信息等)。
accept函数非常地痴情,痴心不改:
如果没有客户端套接字去请求,它便会在那里一直痴痴地等下去,直到永远(注意, 此处讨论的是阻塞式的socket. 如果是非阻塞式的socket, 那么accept函数就没那么痴情了, 而是会立即返回, 并意犹未尽地对未来的客户端扔下一句话: 我等了你, 你不来, 那就算了, 我懒得鸟你)。
来看看accpt函数的用法:
unsigned int sockConn = accept(sockSrv,(SOCKADDR*)&addrClient, &len);
要睡觉了。睡觉之前,最后来看看linux中的accept:
ubuntu@VM-0-15-ubuntu:~$ man accept
ACCEPT(2) Linux Programmer's Manual ACCEPT(2)
NAME
accept, accept4 - accept a connection on a socket
SYNOPSIS
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <sys/socket.h>
int accept4(int sockfd, struct sockaddr *addr,
socklen_t *addrlen, int flags);
DESCRIPTION
The accept() system call is used with connection-based socket types (SOCK_STREAM, SOCK_SEQPACKET). It
extracts the first connection request on the queue of pending connections for the listening socket, sockfd,
creates a new connected socket, and returns a new file descriptor referring to that socket. The newly cre[m
ated socket is not in the listening state. The original socket sockfd is unaffected by this call.
The argument sockfd is a socket that has been created with socket(2), bound to a local address with bind(2),
and is listening for connections after a listen(2).
The argument addr is a pointer to a sockaddr structure. This structure is filled in with the address of the
peer socket, as known to the communications layer. The exact format of the address returned addr is deter[m
mined by the socket's address family (see socket(2) and the respective protocol man pages). When addr is
NULL, nothing is filled in; in this case, addrlen is not used, and should also be NULL.
The addrlen argument is a value-result argument: the caller must initialize it to contain the size (in bytes)
of the structure pointed to by addr; on return it will contain the actual size of the peer address.
The returned address is truncated if the buffer provided is too small; in this case, addrlen will return a
value greater than was supplied to the call.
If no pending connections are present on the queue, and the socket is not marked as nonblocking, accept()
blocks the caller until a connection is present. If the socket is marked nonblocking and no pending connec[m
tions are present on the queue, accept() fails with the error EAGAIN or EWOULDBLOCK.
In order to be notified of incoming connections on a socket, you can use select(2) or poll(2). A readable
event will be delivered when a new connection is attempted and you may then call accept() to get a socket for
that connection. Alternatively, you can set the socket to deliver SIGIO when activity occurs on a socket;
see socket(7) for details.
For certain protocols which require an explicit confirmation, such as DECNet, accept() can be thought of as
merely dequeuing the next connection request and not implying confirmation. Confirmation can be implied by a
normal read or write on the new file descriptor, and rejection can be implied by closing the new socket.
Currently only DECNet has these semantics on Linux.
If flags is 0, then accept4() is the same as accept(). The following values can be bitwise ORed in flags to
obtain different behavior:
SOCK_NONBLOCK Set the O_NONBLOCK file status flag on the new open file description. Using this flag saves
extra calls to fcntl(2) to achieve the same result.
SOCK_CLOEXEC Set the close-on-exec (FD_CLOEXEC) flag on the new file descriptor. See the description of
the O_CLOEXEC flag in open(2) for reasons why this may be useful.
RETURN VALUE
On success, these system calls return a nonnegative integer that is a descriptor for the accepted socket. On
error, -1 is returned, and errno is set appropriately.
Error handling
Linux accept() (and accept4()) passes already-pending network errors on the new socket as an error code from
accept(). This behavior differs from other BSD socket implementations. For reliable operation the applica[m
tion should detect the network errors defined for the protocol after accept() and treat them like EAGAIN by
retrying. In the case of TCP/IP, these are ENETDOWN, EPROTO, ENOPROTOOPT, EHOSTDOWN, ENONET, EHOSTUNREACH,
EOPNOTSUPP, and ENETUNREACH.
ERRORS
EAGAIN or EWOULDBLOCK
The socket is marked nonblocking and no connections are present to be accepted. POSIX.1-2001 and
POSIX.1-2008 allow either error to be returned for this case, and do not require these constants to
have the same value, so a portable application should check for both possibilities.
EBADF The descriptor is invalid.
ECONNABORTED
A connection has been aborted.
EFAULT The addr argument is not in a writable part of the user address space.
EINTR The system call was interrupted by a signal that was caught before a valid connection arrived; see
signal(7).
EINVAL Socket is not listening for connections, or addrlen is invalid (e.g., is negative).
EINVAL (accept4()) invalid value in flags.
......
睡觉。