服务端准备连接的过程
创建套接字
int socket(int domain, int type, int protocol)
- domain 就是指 PF_INET、PF_INET6 以及 PF_LOCAL 等,表示什么样的套接字
- type 可用的值是:
- SOCK_STREAM: 表示的是字节流,对应 TCP;
- SOCK_DGRAM: 表示的是数据报,对应 UDP;
- SOCK_RAW: 表示的是原始套接字。参数 protocol 原本是用来指定通信协议的
- 参数 protocol 原本是用来指定通信协议的,但现在基本废弃。因为协议已经通过前面两个参数指定完成。protocol 目前一般写成 0 即可。
bind: 设定电话号码
为了让别人使用,绑定号码
bind(int fd, sockaddr * addr, socklen_t len)
- sockaddr * addr,通用地址格式
- len 字段表示的就是传入的地址长度,它是一个可变值。
INADDR_ANY 来完成通配地址的设置(编写应用程序时并不清楚自己的应用程序将会被部署到哪台机器上)
listen:接上电话线,一切准备就绪
服务器处于可接听的状态,
int listen (int socketfd, int backlog)
- socketfd 为套接字描述符,
- 第二个参数 backlog,未完成连接队列的大小,这个参数的大小决定了可以接收的并发数目
accept: 电话铃响起了……
int accept(int listensockfd, struct sockaddr *cliaddr, socklen_t *addrlen)
- listensockfd,通过 bind,listen 一系列操作而得到的套接字
- cliadd 是通过指针方式获取的客户端的地址,addrlen 告诉我们地址的大小
客户端发起连接的过程
connect: 拨打电话
int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen)
- servaddr 和 addrlen 分别代表指向套接字地址结构的指针和该结构的大小
- 套接字的地址结构必须包含服务器ip地址和端口号
- 客户在调用函数 connect 前不必非得调用 bind 函数,内核会确定源 IP 地址,按照算法选择一个临时端口作为源端口。
tcp调用connect函数三次握手报错的几种情况:
- 1.无法建立,客户端发送SYN包没有任何响应,返回TIMEOUT错误,错误原因是对应的服务端IP写错
- 2.客户端收到RST回答,客户端返回CONNECTION REFUSED错误,原因是客户端发送链接请求端口写错,因为RST是TCP发送错误时发送的一种TCP分节,
产生RST的三个条件:
1).目的某端口是SYN到达,然而该端口上没有正在监听的服务器
2).TCP想取消一个已有连接
3).TCP接受到一个根本不存在的连接的分支 - 3.客户端发出的SYN包在网络引起“destination unreachable“(目的不可达错误),原因是双方路由不通。
这个模型都阻塞式:调用发起后不会直接返回,由操作系统内核处理之后才返回。
3次握手解读:
服务端通过socket,bind和listen完成被动套接字准备工作,被动等人连接,然后调用accept,就会阻塞到这里,等待客户端的连接来临;客户端通过调用socket和connect函数之后,也会阻塞。接下来是操作系统内核完成网络协议栈工作。
- c向s发送SYN包,告诉s当前发送序列号j,c进入SYNC_SENT状态
- s协议栈收到这个包之后,和c进行ack应答,应答值为j+1,表示SYN包j的确定,同时s发送一个SYN包,告诉c序列号为k,服务端进去SYNC_RCVD状态。
- c收到ACK之后,使应用程序从connect调用返回,表示c到s单向连接建立成功,c状态为ESTABLISHED,同时c也会对s的SYN包进行应答,应答数据为k + 1;
- 应答包到达s后,s使得accept阻塞调用返回,此时s到c单向连接也建立成功,s也进入established状态。
tcp连接的双方要确保各自的收发消息的能力都是正常的。
客户端第一次发送握手消息到服务端,
服务端接收到握手消息后把ack和自己的syn一同发送给客户端,这是第二次握手,
当客户端接收到服务端发送来的第二次握手消息后,客户端可以确认“服务端的收发能力OK,客户端的收发能力OK”,但是服务端只能确认“客户端的发送OK,服务端的接收OK”,
所以还需要第三次握手,客户端收到服务端的第二次握手消息后,发起第三次握手消息,服务端收到客户端发送的第三次握手消息后,就能够确定“服务端的发送OK,客户端的接收OK”,
至此,客户端和服务端都能够确认自己和对方的收发能力OK,,tcp连接建立完成。