server-api-accept

原型

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 created socket is not in the listening state. The original socket sockfd is unaffected by this call.

从已完成连接队列返回第一个连接,如果已完成连接队列为空,则阻塞

函数原型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// sockfd
// 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).
// 要处理连接监听处理的服务器套接字
// addr
// 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 determined 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.
// 将返回要连接方的套接字地址信息
// addrlen
// 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.
// 返回要连接方的套接字地址信息长度
//
// return:
// 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.
// 成功返回0,失败返回-1且会设置errno的值
//
// error:
// EAGAIN or EWOULDBLOCK
// The socket is marked nonblocking and no connections are present to be accepted. POSIX.1-2001 allows either error to be returned for this case, and does not require these constants to have the same value, so a por‐table 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.
// 参数addr指针指向无法存取的内存空间。
// EINTR
// The system call was interrupted by a signal that was caught before a valid connection arrived; see sig‐nal(7).
// EINVAL
// Socket is not listening for connections, or addrlen is invalid (e.g., is negative).
// EINVAL
// (accept4()) invalid value in flags.
// EMFILE
// The per-process limit of open file descriptors has been reached.
// ENFILE
// The system limit on the total number of open files has been reached.
// ENOBUFS, ENOMEM
// Not enough free memory. This often means that the memory allocation is limited by the socket buffer lim‐its, not by the system memory.
// 系统的缓冲区或内存不足。
// ENOTSOCK
// The descriptor references a file, not a socket.
// 套接字为文件描述符,非socket。
// EOPNOTSUPP
// The referenced socket is not of type SOCK_STREAM.
// 指定的socket并非SOCK_STREAM。
// EPROTO
// Protocol error.
// EPERM
// Firewall rules forbid connection.
// 防火墙拒绝此连线。
//
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

使用参考

支持一个客户端的回射服务器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>

#define ERR_EXIT(m)\
do\
{\
perror(m); \
exit(EXIT_FAILURE); \
}while (0)

int main(void)
{
int listenfd;
/*if ((listenfd = socket(PF_INET, SOCK_STREAM, 0))<0)*/
if ((listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
ERR_EXIT("socket");

struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(5188);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
/*servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");*/
/*inet_aton("127.0.0.1", &servaddr.sin_addr);*/

int on = 1;
if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
ERR_EXIT("SETSOCKOPT") ;

if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
ERR_EXIT("BIND");

if (listen(listenfd, SOMAXCONN) < 0)
ERR_EXIT("LISTEN");

struct sockaddr_in peeraddr;
socklen_t peerlen = sizeof(peeraddr);
int conn;
if ((conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen)) < 0)
ERR_EXIT("ACCEPT");

printf("ip=%s port=%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));

char recvbuf[1024];
while (1)
{
memset(recvbuf, 0, sizeof(recvbuf));
int ret = read(conn, recvbuf, sizeof(recvbuf));
fputs(recvbuf, stdout);
write(conn, recvbuf, ret);
}

close(conn);
close(listenfd) ;

return 0;
}