【lesson61】网络套接字

文章目录

  • 理解MAC地址和IP地址
  • 认识端口号
  • 理解 "端口号" 和 "进程ID"
  • 理解源端口号和目的端口号
  • 认识TCP协议
  • 认识UDP协议
  • 网络字节序
  • socket编程接口
    • socket 常见API
    • sockaddr结构

理解MAC地址和IP地址

例子:
我们看西游记每当唐僧到一个地方就会说==“贫僧自东土大唐来,去往西天拜佛求经”==。
东土大唐:源IP地址
西天:目的IP地址

那么什么是MAC地址
比如唐僧到了车迟国,他不知道下一站要去哪,于是就问车迟国国王说“国王我要去西天拜佛求经,下一站该去那哪里?”,国王想了想说“下一站该去车迟国三清观”。
车迟国:源MAC地址
车迟国三清观:目的MAC地址。

等唐僧到了三清观下一站该去往通天河那么
三清观:源MAC地址
通天河:目的MAC地址

所以源IP和目的IP是不会变的,而源MAC和目的MAC地址是随时有可能发生改变。

认识端口号

端口号(port)是传输层协议的内容.

  • 端口号是一个2字节16位的整数;
  • 端口号用来标识一个进程, 告诉操作系统, 当前的这个数据要交给哪一个进程来处理;
  • IP地址 + 端口号能够标识网络上的某一台主机的某一个进程;
  • 一个端口号只能被一个进程占用.

理解 “端口号” 和 “进程ID”

我们之前在学习系统编程的时候, 学习了 pid 表示唯一一个进程; 此处我们的端口号也是唯一表示一个进程. 那么这两者之间是怎样的关系?
这是两套不同的概念,进程ID属于Linux系统编程,端口号属于网络编程,所以不同。
但是他们相同的点就是,都能表示进程唯一性。
另外, 一个进程可以绑定多个端口号; 但是一个端口号不能被多个进程绑定;

理解源端口号和目的端口号

传输层协议(TCP和UDP)的数据段中有两个端口号, 分别叫做源端口号和目的端口号. 就是在描述 “数据是谁发的, 要发给谁”;

网络通信实际是两台机器的两个软件进行通信。
真正网络通信过程本质其实是进程间通信!
将数据在主机间转发仅仅只是手段,需要将数据交付给指定的进程!

端口号是标识特定主机上网络进程的唯一性

任何一个发出的报文一定带有:IP和port

认识TCP协议

此处我们先对TCP(Transmission Control Protocol 传输控制协议)有一个直观的认识; 后面我们再详细讨论TCP的一些细节问题.

  • 传输层协议
  • 有连接
  • 可靠传输
  • 面向字节流

认识UDP协议

此处我们也是对UDP(User Datagram Protocol 用户数据报协议)有一个直观的认识; 后面再详细讨论.

  • 传输层协议
  • 无连接
  • 不可靠传输
  • 面向数据报

网络字节序

我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分, 网络数据流同样有大端小端之分. 那么如何定义网络数据流的地址呢?

  • 发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出;
  • 接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存;
  • 因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址.
  • TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节.
  • 不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据;
  • 如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可

为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换
【lesson61】网络套接字_第1张图片

  • 这些函数名很好记,h表示host,n表示network,l表示32位长整数,s表示16位短整数
  • 例如htonl表示将32位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。
  • 如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回;
  • 如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回;

socket编程接口

socket 常见API

// 创建 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);

sockaddr结构

socket API是一层抽象的网络编程接口,适用于各种底层网络协议,如IPv4、IPv6,以及后面要讲的UNIX Domain Socket. 然而, 各种网络协议的地址格式并不相同

常见的套接字:
1.域间套接字----某主机本地之间的通信
2.原始套接字-----编写的工具(常作为底层人开发的工具)
3.网络套接字----就是我们现在要学的TCP、IP等

理论上三种应用场景应该对应三套接口---->但是Linux不想设计过多接口,所以将所有套接字接口统一。

【lesson61】网络套接字_第2张图片

  • IPv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体表示,包括16位地址类型,16位端口号和32位IP地址.
  • IPv4、IPv6地址类型分别定义为常数AF_INET、AF_INET6. 这样,只要取得某种sockaddr结构体的首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容.
  • socket API可以都用struct sockaddr *类型表示, 在使用的时候需要强制转化成sockaddr_in;这样的好处是程序的通用性, 可以接收IPv4, IPv6, 以及UNIX DomainSocket各种类型的sockaddr结构体指针做为参数

在这里插入图片描述
【lesson61】网络套接字_第3张图片
虽然socket api的接口是sockaddr, 但是我们真正在基于IPv4编程时, 使用的数据结构是sockaddr_in; 这个结构里主要有三部分信息: 地址类型, 端口号, IP地址

【lesson61】网络套接字_第4张图片
in_addr用来表示一个IPv4的IP地址. 其实就是一个32位的整数;

你可能感兴趣的:(linux,网络,Linux)