TCP客户端和服务端所需的基本套接字。服务器先启动,之后的某个时刻客户端启动并试图连接到服务器。之后客户端向服务器发送请求,服务器处理请求,并给客户端一个响应。该过程一直持续下去,直到客户端关闭,给服务端发送EOF(文件结束),服务器也关闭连接的服务器端,然后结束运行或者等待新的客户发起连接请求
图1 TCP网络套接字示意图
在图中涉及到不同的函数,接下来进行详细的介绍。
为了进行网络I/O,进程首先需要调用socket函数,指定使用的通信协议类型(IPv4的TCP、IPv6的UDP、Inux域字节流协议等)。
#include<sys/socket.h>
int socket(int family, int type, int protocol);
返回:若成功返回非负数,若失败返回-1
family表示协议族,协议族取值如表1所示:
family | 说明 |
---|---|
AF_INET | IPv4协议 |
AF_INET6 | IPv6协议 |
AF_LOCAL | Unix域协议 |
AF_ROUTE | 路由套接字 |
AF_KEY | 密钥套接字 |
表1 协议族family取值
type表示套接字类型,套接字类型type如表2所示:
type | 说明 |
---|---|
SOCK_STREAM | 字节流套接字 |
SOCK_DGRAM | 数据报套接字 |
SOCK_SEQPACKET | 有序分组套接字 |
SOCK_RAW | 原始套接字 |
表2 套接字类型
protocol表示某个协议类型常值,或者设置为0,以选择family和type组合的系统默认值,但并不是所有的family和type组合都是有效的,表3给出了正确组合。
表3 偷来的截图
socket函数调用成功后返回一个小的非负整数值,称为套接字描述符(socket descriptor),简称sockfd。指定了协议族(IPv4、Ipv6或Unix)和套接字类型(字节流、数据报或原始套接字),并没有指定本地协议地址或远程协议地址。
TCP客户端使用connect函数来建立与TCP服务器之间的连接。
#include<sys/socket.h>
int connect(int sockfd, const struct *servaddr, socklen_t addrlen);
返回:若成功返回0,若失败返回-1
sockfd:socket函数返回的套接字描述符
servaddr:套接字地址结构的指针
addrlen:套接字地址结构的大小
套接字地址结构必须含有服务器的IP地址和端口号。客户端在调用connect函数前不必非要调用bind函数,因为如果需要的话,内核会确认源IP地址,并选择一个临时端口作为源端口。
如果是TCP套接字,调用connect函数会激发TCP三次握手,而且仅在连接建立成功或失败时才会返回。
bind函数将一个本地协议地址赋予一个套接字,对于网际协议,协议地址是32位的Ipv4地址或128位的IPv6地址与16位的TCP或UDP端口号的组合。
#include<sys/socket.h>
int bind(int sockfd, const struct *myaddr, socklen_t addrlen);
返回:若成功返回0,若失败返回-1
sockfd:socket函数返回的套接字描述符
servaddr:套接字地址结构的指针
addrlen:套接字地址结构的大小
对于TCP,调用bind函数可以指定一个端口号和一个IP地址,也可以不指定。