网络字节序:
计算机中存在两种存储字节的方式,分别是:大端存储和小端存储,TCP/IP协议规定,网络数据字节流应采用大端字节序。如果当前发送的主机是小端机就需要将数据转化为大端,再发送。
小端存储:
- 数据的低位字节存储到内存的低地址位, 数据的高位字节存储到内存的高地址位
- 我们使用的PC机,数据的存储默认使用的是小端
大端存储:
- 低位字节存储到高地址位处,高位字节存储到低地址位处
- 套接字通信的存储是大端存储
端口号:
端口号(port)是传输层协议的内容.
- 端口号是一个2字节16位的整数;
- 端口号用来标识一个进程, 告诉操作系统, 当前的这个数据要交给哪一个进程来处理;
- IP地址 + 端口号能够标识网络上的某一台主机的某一个进程;
- 一个端口号只能被一个进程占用
什么是socket?
IP+端口号就叫socket,IP是每一台主机唯一的标识符,而端口号在同一台主机上也是唯一的。
网络通信的本质其实就是进程间通信
问题:每一个进程都有自己的pid,而且pid都是唯一的,为什么还需要额外用端口号来找到进程呢?
进程中有需要网络通信的进程也有不需要网络通信的进程,如果拿pid通信,就区分不了哪些进程是不需要通信的,有端口号的进程可以进行网络通信,没有端口号的就不需要网络通信,通过有无端口号对进程是否需要通信做区分
套接字函数:
int socket(int domain, int type, int protocol)
- domain:使用地址簇协议
- AF_INET: 使用IPv4格式的ip地址
- AF_INET6: 使用IPv6格式的ip地址
- type:
- SOCK_STREAM: 使用流式的传输协议
- SOCK_DGRAM: 使用报式(报文)的传输协议
- protocol:一般写0,使用默认协议
SOCK_STREAM: 流式传输默认使用的是tcp
SOCK_DGRAM: 报式传输默认使用的udp
返回值:调用成功,返回文件描述符,调用失败,返回-1
该函数的返回值是一个文件描述符,通过该文件描述符,可以操作内核中的某一块内存
int listen(int sockfd, int backlog);
- socket:文件描述符, 可以通过调用socket()得到,在监听之前必须要绑定 bind()
- backlog:同时能处理的最大连接要求,最大值为128
- 返回值:函数调用成功返回0,调用失败返回 -1
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
- sockfd: 监听的文件描述符
- addr: 传出参数, 里边存储了建立连接的客户端的地址信息
- addrlen: 传入传出参数,用于存储addr指向的内存大小
- 返回值:函数调用成功,得到一个文件描述符, 用于和建立连接的这个客户端通信,调用失败返回 -1
这是一个阻塞函数,当没有新的客户端连接请求时,就会发生阻塞,有新的客户端发送请求时,阻塞解除,建立新链接,返回值为一个文件描述符,通过这个文件描述符建立通信
接受数据的函数
ssize_t read(int sockfd, void *buf, size_t size);
ssize_t recv(int sockfd, void *buf, size_t size, int flags);
- sockfd: 用于通信的文件描述符, accept() 函数的返回值
- buf: 指向一块有效内存, 用于存储接收是数据
- size: 参数buf指向的内存的容量
- flags: 特殊的属性, 一般不使用, 指定为 0
- 返回值:
- 大于0:实际接受的字节数
- =0:对方断开了链接
- <0:接收数据失败
如果链接没有断开,接收端接收数据失败,那么接收数据的函数就会阻塞等待数据的到来,数据到达后阻塞解除。当发送端断开连接,接收端无法接收到任何数据,函数不会阻塞,直接返回0
发送数据的函数
ssize_t write(int fd, const void *buf, size_t len);
ssize_t send(int fd, const void *buf, size_t len, int flags);
- fd: 通信的文件描述符, accept() 函数的返回值
- buf: 传入参数, 要发送的字符串
- len: 要发送的字符串的长度
- flags: 特殊的属性, 一般不使用, 指定为 0
- 返回值:
- >0:实际发送的字节数,和参数len是相等的
- -1:发送数据失败了
// 成功连接服务器之后, 客户端会自动随机绑定一个端口
// 服务器端调用accept()的函数, 第二个参数存储的就是客户端的IP和端口信息
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- sockfd: 通信的文件描述符, 通过调用socket()函数就得到了
addr: 存储了要连接的服务器端的地址信息: iP 和 端口,这个IP和端口也需要转换为大端然后再赋值
addrlen: addr指针指向的内存的大小 sizeof(struct sockaddr)
返回值:连接成功返回0,连接失败返回-1
TCP通信流程:
TCP是一个面向连接的,安全的,流式传输协议,该协议是一个传输层协议
- 传输层协议
- 有链接
- 可靠传输
- 面向字节流