socket()函数: 产生TCP套接字,作为TCP通信的传输端点。
#include
int socket(intfamily, int type, int protocol);
返回一个小的非负的整数,与文件描述符类似,即套接字描述符。
family :socket协议类型, AF_INET(IPV4),AF_INET6(IPV6), AF_ROUTE(路由套接口)
type: 套接字类型,SOCK_STREAM, SOCK_DGRAM, SOCK_RAW.
connect函数:激发TCP的三次握手协议,建立与TCP服务器的连接。
#include
int connect(intsockfd, const struct sockaddr* addr, socklen_taddrlen);
调用成功返回0,失败返回-1(响应超时,目标不可达或服务器端口没有服务)。
addr(通用的套接字) 是指向服务器的套接字地址结构的指针。
注意:若函数connect调用失败,则套接字不能再使用,必须关闭。如果想继续向服务器发起建立连接的请求,需要重新调用socket()函数参数套接字。
bind()函数:为调用socket()函数产生的套接字分配一个本地协议地址,建立地址与套接字的关系。
#include
int bind(intsockfd, const struct sockaddr *server, socklen_len addrlen);
调用成功返回0,出错-1,并置错误号errno.
server 指向特定于协议的地址结构的指针,指定用于通信的本地地址协议。
对于绑定的套接字地址结构,可以指定端口号或IP地址的任意一个。若不指定端口,内核会为套接字选择一个临时的端口。
客户端一般不需要调用bind(), 由内核来选择IP源地址。如果服务器不绑定IP,就把客户端发来的目的地址作为服务器源IP(服务器不绑定IP,如何接收?)
listen() 函数:将未连接的套接字转换成被动套接字,使它处在被监听模式下,指示内核应接受发向该套接字的连接请求。
int listen(intsockfd, int backlog);
backlog:请求队列中的最大连接数,对队列中等待服务请求的数目进行了限制。
accept()函数:使服务器接收客户端的连接请求,并产生一个新的套接字描述符,“已连接套接字”。没有请求时进程堵塞睡眠
int accept(intlistenfd, struct sockaddr * client, socklen_t *addrlen);
listenfd 其实就是sockfd,不过就是在accept之前调用listen()将主动套接字转换成了被动监听套接字。 函数返回 已连接套接字描述符,对应具体客户端。
client 和addrlen 用来返回连接对方的套接字地址结构和对应的结构长度。
addrlen是值-结构参数。
数据传输函数:当服务器和客户端的连接建立后,可以进行双向的数据传输了,套接字描述符也是一种文件描述符,可以使用文件读/写函数。
#include
int write(intsockfd, char *buf, int len);
int read(intsckfd, char *buf, int len);
#include
#include
ssize_t send (intsockfd, const void *buf, size_t len, int flags);
ssize_t revc (intsockfd, void *buf, size_t len, int flags);
close()函数:关闭套接字,并立即返回到进程。
TCP试着将已排队的待发送数据发送完,然后按照正常TCP连接终止的操作关闭连接。close关闭描述符,其实只是将描述符的访问计数减1,如果描述符的访问计数仍>0, 不会引发TCP的终止连接操作,在并发服务器上非常重要。
#include
int close(intsockfd);
服务器的三种异常情况:
1. 服务器主机崩溃
2. 服务器主机崩溃后重启
3. 服务器主动关闭:
客户工作时有两个描述符:套接字和标准输入,服务器主动关闭时会给客户端发送FIN字节,但是当FIN到达套接字是,客户正阻塞于标准输入fgets调用,无法立即接收,使得他不能正常处理服务器的关闭,对于客户,它不能只阻塞于套接字中的任何一个,这就需要在客户端使用select或Poll函数,使得客户在服务器进程开始终止时就能检测到。