###########################################################
TCP套接字编程相关的系统调用(内核中的传输层):
###########################################################
大多数TCP服务器是并发的,需要用到fork和exec。
父进程关闭已连接套接字描述符connfd,父进程可以接着处理其它客户的连接请求。
子进程关闭监听套接字描述符listenfd,子进程通过connfd和客户进行通信,完成后用close或exit来关闭子进程的connnfd。
已连接套接字描述符每个客户和服务器连接后都有一个,监听套接字描述符一个服务器一般只有一个。
客户端用socket函数来获取一个未命名套接字描述符:
服务端用socket函数来获取一个监听套接字描述符:
int listenfd = int
socket(int family, int type, intprotocol);
socket的参数都是和协议相关的。
family:(网络层协议)
分两种,一般用地址族。
bsd和linux:(AF:地址族)
AF_INET(ipv4域)
AF_INET6(ipv6域)
AF_LOCAL(unix域)=AF_UNIX
AF_ROUTE(路由域)
AF_KEY(秘钥域)
AF_PACKET
svr4:(PF:协议族)
PF_INET
PF_INET6
PF_UNIX
PF_NCA
type:
SOCK_STREAM(字节流套接字)(tcp、sctp)
SOCK_DGRAM(数据报套接字)(udp)
SOCK_SEQPACKET(有序分组套接字)(sctp)
SOCK_RAW(原始套接字)(ipv4、ipv6)
SOCK_RDM(无序可靠数据报套接字)
protocol:(传输层协议)
0:tcp和udp,一般用这个,表示默认值
IPPROTO_SCTP: sctp用这个。
客户用connect建立客户端未命名套接字和服务监听套接字的连接:
考虑超时问题
int connect(int sockfd, const struct sockaddr *servaddr, socklen_taddrlen);
sockfd:socket()返回的套接字描述符
struct sockaddr:通用套接字地址结构
addrlen:结构的长度
后两个参数就是服务器的通用套接字地址结构和长度,必须填写。
调用bind函数把一个地址和端口赋予一个套接字(给套接字命名):
在建立连接之前如果没有调用bind,内核会选择一个IP和端口号给套接字。
int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrltn);
sockfd:socket()返回的套接字描述符
struct sockaddr:ipv4通用套接字地址结构
addrlen:结构的长度,sizeof(struct sockaddr)
如果为通配地址且为INADDR_ANY=0,表示bind时由内核选择IP;
如果用指定的本地IP,就用指定的IP。
如果端口号为0,表示bind时由内核选择端口号;
如果端口号不为0,就用指定的端口。
TCP服务调用listen函数来创建队列保存未处理的请求:
int listen(int sockfd, int backlog);
backlog:规定内核应该为相应套接字排队的最大连接个数。
连接队列:
未完成队列:三路握手未完成
已完成队列:三路握手完成
TCP服务调用accept函数用来接受连接;
并返回一个新的专用的套接字描述符:
考虑超时问题
int cOnnfd= int
accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);
成功返回:已连接套接字描述符
sockfd:监听套接字描述符
cliaddr:返回客户的协议地址
addrlen:返回客户的协议地址的大小, sizeof(struct sockaddr)
后两个参数就是服务器返回的客户端的通用套接字地址结构和长度,不需要可以忽略。
发送数据:
write(一般用这个)
send
sendmsg
sendto(不能指定IP和端口号)
接收数据:
read(一般用这个)
recv
recvmsg
recvfrom(不返回IP和端口号)
关闭套接字描述符:
int close(int sockfd);
close有两个限制:
1. close把描述符的引用计数减1,仅在计数变为0才关闭套接字。
2. close终止读和写两个方向的数据传送。
关闭套接字描述符:
int shutdown(int sockfd, int how);
how:
SHUT_RD=0:关闭读这一半,套接字中不再有数据可接收,套接字接收缓冲区中的数据也清空。
SHUT_WR=1:关闭写这一半,在套接字发送缓冲区中的数据会被发送出去,然后正常终止连接。
SHUT_RDWR=2:关闭读和写
返回与某个套接字关联的本地协议地址:
int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t*addrlen);
返回sockfd的通用套接字地址结构和长度。
返回与某个套接字关联的对端协议地址:
int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen);
sockets: TCP