目录
一丶概念梳理
1.源IP和目的IP
之前学习到的两个计算机之间想要进行通信,就要定一种协议但是这些都是基于知道对方主机的IP和端口号的。两个主机都需要知道对方的IP~
2.源端口和目的端口
想要进行主机与主机之间的通信工作必须要知道彼此之间的IP和端口号缺一不可,那么端口号的作用就是对方主机哪个程序的唯一标识·也被称之为程序地址~
对于源IP地址和目的IP地址,就是确定了哪两台主机要通信;
对于源端口号和目的端口号,就是确定了两台主机上的哪两个进程要进行通信;
3.通信识别
通过IP+端口号和通信协议就可以确定一个网络通信~
- IP地址最大的意义在于指导一个报文该如何进行路径选择,到哪里去就是去找目标IP地址。
- 端口号的意义在于唯一的标识一台机器上的唯一一个进程。
- IP地址 + 端口号 = 能够标识互联网中的唯一一个进程!
- IP地址 + port(端口号) = socket(套接字)
进程ID与端口号的理解:
每个进程都需要有自己的PID用来标识,但是有的进程是系统进程,有的是网络进程。所以说不是所有的进程都需要端口号。但是一个进程可以绑定多个端口号。但是一个端口号不能被多个进程绑定~
4.UDP协议和TCP协议
1.UDP协议特点
UDP是 User Datagram Protocol 的缩写,即用户数据报协议。
UDP不提供复杂的控制机制,利用IP提供面向无连接的通信服务。并且它是将应用程序发来的数据在收的那一刻,立即按照原样发送到网络上的一种机制。
- 传输层协议
- 无连接
- 不可靠传输
- 面向数据报
2.TCP协议特点
TCP是 Transmission Control Protocol 的缩写,即传输控制协议。
TCP与UDP的区别相当大。它充分地实现了数据传输时的各种控制功能,可以进行丢包时重发控制,还可以对次序乱掉的分包进行顺序控制。而这些再UDP中都没有。此外,TCP作为一种面向有连接的协议,只要在确认通信对端存在时才会发生数据,从而可以控制通信流量的浪费。
- 传输层协议
- 有连接
- 可靠传输
- 面向字节流
总之UDP是无连接通信,TCP是有连接通信。无连接通信特点在于客户端只需给用户提供服务,不用关心提供服务之后的事情
有连接通信特点在于给用户提供过服务之后。需要关心后续的状态~
5.网络字节序
1.大端字节序与小端字节序
- 大端模式: 数据的高字节内容保存在内存的低地址处,数据的低字节内容保存在内存的高地址处。
- 小端模式: 数据的高字节内容保存在内存的高地址处,数据的低字节内容保存在内存的低地址处。
2.字节序
与同一台计算机上的进程进行通信时,一般不考虑字节序。字节序是一个处理器架构特性,用于指示像整数这样的大数据类型内部的字节如何排序。但如果涉及网络通信,那就必须考虑大小端的问题,否则对端主机识别出来的数据可能与发送端想要发送的数据是不一致的。
TCP/IP协议栈使用大端字节序。应用程序交换格式化数据时,字节序问题就会出现。对TCP/IP,地址用网络字节序来表示,所以应用程序有时候需要在处理器的字节序与网络字节序之间进行转换。以确保数据的一致性。
对于TCP/IP应用程序,有四个用来在处理器字节序和网络字节序之间实施转换的函数。
#include <arpa/inet.h> uint32_t htonl(uint32_t hostlong); //返回值:以网络字节序表示的32位整数 uint16_t htons(uint16_t hostshort); //返回值:以网络字节序表示的16位整数 uint32_t ntohl(uint32_t netlong); //返回值:以主机字节序表示的32位整数 uint16_t ntohs(uint16_t netshort); //返回值:以主机字节序表示的16位整数
h表示“主机”字节序,n表示“网络”字节序。
l表示“长”整数,s表示“短”整数。
6.地址转换函数
有时候,我们需要打印出被人能理解的地址格式(如:12.0.0.1)而不是被计算机理解的地址格式(32位二进制数),那么就需要用到以下函数。
它们在ASCII字符串(这是人们偏爱使用的格式)与网络字节序的二进制值(这是存放在套接字地址结构中的值)之间转换网际地址。
#include <arpa/inet.h> int inet_aton(const char* strptr, struct in_addr* addrptr); in_addr_t inet_addr(const char* strptr); char* inet_ntoa(struct in_addr addrptr);
inet_aton函数
该函数将strptr所指C字符串转换成一个32位的网络字节序二进制值,并且通过指针addrptr来存储。若成功则返回1,否则返回0;
如果addrptr指针为空,那么该函数仍然对输入的字符串执行有效检查,但不存储任何结果。
inet_ntoa函数
该函数讲一个32位的网络字节序二进制IPV4地址转换成相应的点分十进制数串。由该函数的返回值所指向的字符串驻留在静态内存中。
inet_addr函数
与inet_aton一样进行相同的转换,返回值为32的网络字节序二进制值。
二丶socket编程接口
1.socket常见API
//创建套接字 int socket(int domain, int type, int protocol); //绑定端口 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); //监听套接字 int listen(int sockfd, int backlog); //接受请求 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); //建立连接 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
1.创建套接字:
// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器) int socket(int domain, int type, int protocol);
想要进行网络编程就必须创建一个套接字。打开网络文件,
domain:
指明协议族,即你想要使用什么协议(IPV4、IPV6...),它是下列表格中的某个常值。该参数也往往被称为协议域。
domain 功能