本章详细描述了socket函数的用法,参数说明等基本知识。下面我们一一介绍:
首先是函数
int socket (int family, int type, int protocol);
Returns: non-negative descriptor if OK, -1 on error
其中family指定了协议族,有以下几个常量:AF_INET是IPv4的协议族,AF_INET6是IPv6的协议族,AF_LOCAL是unix的协议族(domain protocol)还有AF_ROUTE和AF_KEY。
type是以下常量之一:SOCK_STREAM,SOCK_DGRAM,SOCK_SEQPACKET和SOCK_RAW。
protocol必须指定为IPPROTO_TCP,IPPROTO_UDP和IPPROTO_SCTP之一,或者为0让系统自动选择有family和type的组合而定。
下面一个函数是
int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen); |
Returns: 0 if OK, -1 on error |
其中sockfd是由函数socket返回的值。就TCP socket来说,connect初始化“三次握手”过程,连接过程中可能有以下几种错误发生:
- 如果client端没有收到SYN段,那么发生错误并返回ETIMEDOUT。
- 如果客户端收到Server端是RST(reset)的话,说明server端并没有连接可用,返回ECONNREFUSED
- 如果客户端收到ICMP"destination unreachable"则返回EHOSTUNREACH o或者ENETUNREACH
int bind (int sockfd, const struct sockaddr *myaddr, socklen_t addrlen); |
Returns: 0 if OK,-1 on error |
此函数分配一个local address给socket,根据协议族是ipv4还是ipv6而定,同时还分配一个16位的端口号。此函数一个常见的错误是“address already in use”。
int listen (int sockfd, int backlog); |
Returns: 0 if OK, -1 on error |
listen函数有两个功能:
- 当调用socket函数的时候创建了一个可用的socket,次数客户端可能发起一个连接,系统通过listen函数把未连接的socket转变为pasitive的socket,表示内核应该接受这个连接,同时把socket的CLOSED状态转换为LISTEN状态。
- 而第二个功能是指明内核为这个socket排队的最大数目,包括已经完成three-way和未完成的,这里backlog有一个历史遗留的问题,但可以通过环境变量来改变数值。因为之前定的最大是5显然不能应付目前大型服务器的连接数。
int accept (int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen); |
Returns: non-negative descriptor if OK, -1 on error |
TCP server从上面提到的backlog的队列中调用accept去接受完成三次握手的socket连接,如果队列为空,则进程sleep。如果函数成功调用,则返回一个全新的描述符,描述和TCP client的连接。
pid_t fork(void); |
Returns: 0 in child, process ID of child in parent, -1 on error |
最后是一个fork函数,通过fork函数来创建一个子进程来处理每个client的连接。