server-api-socket

原型

create an endpoint for communication

创建一个套接字用于通信

函数原型
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// domain
// The domain argument specifies a communication domain; this selects the proto‐col family which will be used for communication.
// 需要指定的通信协议族(protocol family)
// AF_UNIX, AF_LOCAL
// Local communication
// UNIX 进程通信协议
// AF_INET
// IPv4 Internet protocols
// Ipv4网络协议
// AF_INET6
// IPv6 Internet protocols
// Ipv6 网络协议
// AF_IPX
// IPX - Novell protocols
// IPX-Novell协议
// AF_NETLINK
// Kernel user interface device
// 核心用户接口装置
// AF_X25
// ITU-T X.25 / ISO-8208 protocol
// X.25/ISO-8208 协议
// AF_AX25
// Amateur radio AX.25 protocol
// 业余无线AX.25协议
// AF_ATMPVC
// Access to raw ATM PVCs
// 存取原始ATM PVCs
// AF_APPLETALK
// Appletalk
// appletalk(DDP)协议
// AF_PACKET
// Low level packet interface
// 初级封包接口
// type
// 指定socket类型,流式套接字SOCK_STREAM,数据报套接字SOCK_DGRAM,原始套接字SOCK_RAW
// SOCK_STREAM
// Provides sequenced, reliable, two-way, connection-based byte streams. An out-of-band data transmission mechanism may be supported.
// 提供双向连续且可信赖的数据流,即TCP。支持OOB 机制,在所有数据传送前必须使用connect()来建立连线状态。
// SOCK_DGRAM
// Supports datagrams (connectionless, unreliable messages of a fixed maximum length).
// 使用不连续不可信赖的数据包连接(udp)
// SOCK_SEQPACKET
// Provides a sequenced, reliable, two-way connection-based data transmission path for datagrams of fixed maximum length; a consumer is required to read an entire packet with each input system call.
// 提供连续可信赖的数据包连接
// SOCK_RAW
// Provides raw network protocol access.
// 提供原始网络协议存取
// SOCK_RDM
// Provides a reliable datagram layer that does not guarantee ordering.
// 提供可信赖的数据包连接
// SOCK_PACKET
// Obsolete and should not be used in new programs
// 提供和网络驱动程序直接通信。
// 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.
// 给描述符加上O_NONBLOCK标识,省去fcntl的操作
// SOCK_CLOEXEC
// Set the close-on-exec (FD_CLOEXEC) flag on the new file descriptor.
// 给描述符加上FD_CLOEXEC标识
// protocol
// The protocol specifies a particular protocol to be used with the socket. Normally only a single protocol exists to support a particular socket type within a given protocol family, in which case protocol can be specified as 0. How‐ever, it is possible that many protocols may exist, in which case a particular protocol must be specified in this manner. The protocol number to use is spe‐cific to the “communication domain” in which communication is to take place; see protocols(5). See getprotoent(3) on how to map protocol name strings to protocol numbers.
// 该协议指定了与套接字一起使用的特定协议。 通常,只有一个协议支持给定协议族中的特定套接字类型,在这种情况下协议可以指定为0.但是,可能存在许多协议(如原始套接口),在这种情况下必须指定特定协议。
//
// return:
// On success, a file descriptor for the new socket is returned. On error, -1 is returned, and errno is set appropriately.
// 成功返回一个文件描述符,失败返回-1,并设置errno的值
//
// error:
// EACCES
// Permission to create a socket of the specified type and/or protocol is denied.
// 权限不足,无法建立type或protocol指定的协议
// EAFNOSUPPORT
// The implementation does not support the specified address family.
// 该实现不支持指定的地址族。
// EINVAL
// Unknown protocol, or protocol family not available.
// Invalid flags in type.
// 参数domain/type/protocol不合法
// EMFILE
// Process file table overflow.
// 进程文件表溢出,无法再建立新的socket
// ENFILE
// The system limit on the total number of open files has been reached.
// 系统对打开文件总数的限制已经达到
// ENOBUFS or ENOMEM
// Insufficient memory is available. The socket cannot be created until sufficient resources are freed.
// 内存不足
// EPROTONOSUPPORT
// The protocol type or the specified protocol is not supported within this domain.
// 参数domain指定的类型不支持参数type或protocol指定的协议
//
int socket(int domain, int type, int protocol);

AF_XXX与PF_XXX

AF_前缀代表地址族,PF_前缀代表协议族。历史上曾经有这样的想法;单个协议族可以支持多个地址族,PF_值用来创建套机接口,而AF_值用于套接口地址结构。但实际上,支持多个地址族的协议族从来就未出现过,而且头文件<sys/socket.h>中定义的PF_值总是与次协议的AF_值相对。尽管这种相等关系并不保证永远正确,若有人试图给已有的协议改变这种约定,则许多现存代码都将崩溃。为与现存代码保持一致,推荐使用AF_值

使用参考

支持一个客户端的回射服务器
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
66
67
#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);
// inet_aton("127.0.0.1", &servaddr.sin_addr);
// servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
// servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
inet_pton(AF_INET, "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");

char ip_addr[INET_ADDRSTRLEN] = {0};
printf("ip=%s port=%d\n", inet_ntop(AF_INET, &peeraddr.sin_addr, ip_addr, INET_ADDRSTRLEN), 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;
}