例子:
我们看西游记每当唐僧到一个地方就会说==“贫僧自东土大唐来,去往西天拜佛求经”==。
东土大唐:源IP地址
西天:目的IP地址
那么什么是MAC地址
比如唐僧到了车迟国,他不知道下一站要去哪,于是就问车迟国国王说“国王我要去西天拜佛求经,下一站该去那哪里?”,国王想了想说“下一站该去车迟国三清观”。
车迟国:源MAC地址
车迟国三清观:目的MAC地址。
等唐僧到了三清观下一站该去往通天河那么
三清观:源MAC地址
通天河:目的MAC地址
所以源IP和目的IP是不会变的,而源MAC和目的MAC地址是随时有可能发生改变。
端口号(port)是传输层协议的内容.
我们之前在学习系统编程的时候, 学习了 pid 表示唯一一个进程; 此处我们的端口号也是唯一表示一个进程. 那么这两者之间是怎样的关系?
这是两套不同的概念,进程ID属于Linux系统编程,端口号属于网络编程,所以不同。
但是他们相同的点就是,都能表示进程唯一性。
另外, 一个进程可以绑定多个端口号; 但是一个端口号不能被多个进程绑定;
传输层协议(TCP和UDP)的数据段中有两个端口号, 分别叫做源端口号和目的端口号. 就是在描述 “数据是谁发的, 要发给谁”;
网络通信实际是两台机器的两个软件进行通信。
真正网络通信过程本质其实是进程间通信!
将数据在主机间转发仅仅只是手段,需要将数据交付给指定的进程!
端口号是标识特定主机上网络进程的唯一性
任何一个发出的报文一定带有:IP和port
此处我们先对TCP(Transmission Control Protocol 传输控制协议)有一个直观的认识; 后面我们再详细讨论TCP的一些细节问题.
此处我们也是对UDP(User Datagram Protocol 用户数据报协议)有一个直观的认识; 后面再详细讨论.
我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分, 网络数据流同样有大端小端之分. 那么如何定义网络数据流的地址呢?
为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。
// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);
// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address,
socklen_t address_len);
// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);
// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address,
socklen_t* address_len);
// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
socket API是一层抽象的网络编程接口,适用于各种底层网络协议,如IPv4、IPv6,以及后面要讲的UNIX Domain Socket. 然而, 各种网络协议的地址格式并不相同
常见的套接字:
1.域间套接字----某主机本地之间的通信
2.原始套接字-----编写的工具(常作为底层人开发的工具)
3.网络套接字----就是我们现在要学的TCP、IP等
理论上三种应用场景应该对应三套接口---->但是Linux不想设计过多接口,所以将所有套接字接口统一。
sockaddr_in
结构体表示,包括16位地址类型,16位端口号和32位IP地址.sockaddr结构体指针
做为参数
虽然socket api的接口是sockaddr
, 但是我们真正在基于IPv4编程时, 使用的数据结构是sockaddr_in
; 这个结构里主要有三部分信息: 地址类型, 端口号, IP地址