尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Linux系统之网络基础概念(下)

Linux系统之网络基础概念(下) 本篇目标:1.认识端口号2.了解传输层的典型代表3.网络字节序的掌握4.socket编程接⼝的初步理解一.Socket编程预备1.认识端口号1.1.引入概念首先我们先思考一个问题数据传输到主机是目的吗答案不是的因为数据是给人用的比如我们用微信聊天是两个人之间在聊天下载是人在下载看网页是人从网页中获取数据。但是人是怎么看到聊天信息的呢怎么执行下载任务呢怎么浏览网页信息呢我们是通过启动的qq迅 雷浏览器而启动的qq迅雷浏览器都是进程。结论进程是人在系统中的代表只要把数据给进程就相当于人就拿到了数据数据传输到主机 不是目的而是手段而到达主机内部在交给主机内的进程才是目的。如图解释数据经过网络传输到目标主机完成解包后操作系统还需要判断数据应该交给哪个应用进程。网络层通过 IP 地址标识目标主机传输层则通过端口号标识目标主机中的网络通信端点。内核根据协议、IP 地址和端口号找到对应的 Socket再将数据交给持有该 Socket 的进程。1.2.端口号作用端口号( port )是传输层协议的内容用来标识⼀个进程告诉操作系统当前的这个数据要交给哪一个进程来 处理;大小一个 2 字节 16比特位的整数;特点⼀个端口号只能被⼀个进程占用。那么此时可能有人会问既然PID 已经能够唯一标识进程为什么还要引入端口号而不是直接用 PID 来替代呢答案首先不是所有的进程都要进行网络通信然后理论上用pid是可行的但是没有这个必要因为pid是系统的概念 而端口号是网络的概念如果将pid运用到了网络那万一有一天pid变化了或者突然换了一个新的呢那是不是 网络也要跟着改变这就像办事大厅中的窗口号和工作人员的工号用户需要寻找的是“3号业务窗口”而不是某 位工作人员的工号。即使工作人员发生变化只要3号窗口仍然提供相同的服务用户的访问方式就不需要改变。 所有用端口号而不是pid是为了与系统解耦。通过之前的学习我们已经知道了ip是用来标识全网内唯一的一个主机而端口号是用来标识主机上的一个网络进程所以ip端口号是用来标识全网内唯一的一个进程。我们把ipport 叫做套接字 socket。结论网络通信的本质全网中两个进程之间进行进程间通信两个互联网进程代表⼈来进行通信{srcIp(源ip) srcPort(源port)dstIp(目的ip)dstPort(目的port)} 这样的4元组就能标识互联网中唯二的两个进程。端⼝号范围划分0 - 1023 知名端口号HTTPFTP SSH 等这些广为使用的应用层协议他们的端口号都是固 定的024 - 65535 操作系统动态分配的端口号例如客户端程序的端口号就是由操作系统从这个范 围分配的.2.传输层的典型代表如果我们了解了系统也了解了网络协议栈我们就会清楚传输层是属于内核的那么我们要通过网络协议栈进行通信必定调用的是传输层提供的系统调用来进行的网络通信。如图传输层比较有代表的两个协议就是UDP协议和TCP协议目前我们先对这两个协议有个直观的认识后面再深入理解。2.1.认识TCP协议特点1通信之前双方需要先建立连接例如打电话时电话接通后双方通常会先说“喂听得到吗”确认彼此都能够听见对方的声音然后才开始正式交谈。2.可靠传输。TCP 能够保证数据不丢失; 不重复; 按顺序到达; 出错后能够重传。3.面向字节流。TCP 将应用程序交付的数据视为一串连续的字节不保留应用程序每次发送数据时的边界。例如发送方调用三次send(hello) send(world) send(TCP)接收方可能一次收到helloworldTCP也可能分多次收到。因此一次send()不一定对应一次recv()应用层需要自行设计消息边界。这个字节流目前我们稍微认识一下即可。2.2.认识UDP协议特点1.UDP通信之前不需要建立连接发送方知道对方的 IP 地址和端口号后就可以直接发送数据。例如寄信人只需要填写收件地址并将信寄出不需要先与收件人建立联系。2.不可靠传输。UDP只负责尽力发送数据但不保证数据一定能够到达; 数据按照发送顺序到达; 数据不会重复; 数据丢失后能够自动重传.3.面向数据报UDP会保留应用程序每次发送数据时的边界。例如发送方调用三次sendto(hello) sendto(world) sendto(UDP)UDP会形成三个独立的数据报数据报1hello 数据报2world 数据报3UDP此时还有个问题既然 TCP 比 UDP 更可靠那为什么还需要 UDP 呢直接用 TCP 不就行了吗答案我们不应当将UDP的“不可靠”理解为贬义而应该把它看作一个描述协议特点的中性词。TCP虽然能够提供可靠传 输但这也意味着它需要通过确认应答、超时重传等机制完成更多工作因此协议实现更加复杂占用的系统资源 也相对更多。UDP不提供这些可靠性保证恰恰使它拥有了简单、轻量和灵活的特点。3.网络字节序我们已经知道内存中的多字节数据相对于内存地址有大端和小端之分磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分网络数据流同样有大端小端之分那么如何定义网络数据流的地址呢?• 发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出• 接收主机把从网络上接到的字节依次保存在接收缓冲区中也是按内存地址从低到高的顺序保存• 因此网络数据流的地址应这样规定先发出的数据是低地址后发出的数据是高地址• TCP/IP协议规定网络数据流应采用大端字节序即低地址高字节• 不管这台主机是大端机还是小端机都会按照这个TCP/IP规定的网络字节序来发送/接收数据• 如果当前发送主机是小端就需要先将数据转成大端否则就忽略直接发送即可。如图为使网络程序具有可移植性使同样的C代码在大端和小端计算机上编译后都能正常运行可以调用以下库函数做网络字节序和主机字节序的转换。如图解释• 这些函数名很好记h 表示 hostn 表示 networkl 表示 htonl 表示将 32 位长整数s 表⽰ 16 位短整数htonl表示将32 位的长整数从主机字节序转换为网络字节序例如将IP地址转换后准备发送。• 如果主机是小端字节序这些函数将参数做相应的大小端转换然后返回• 如果主机是大端字节序这些函数不做转换将参数原封不动地返回。4.socket编程接口// 创建 socket 文件描述符,适用于TCP/UDP、客户端/服务器 int socket(int domain, int type, int protocol); // 绑定 IP 地址和端口号,适用于TCP/UDP、服务器 int bind(int sockfd,const struct sockaddr* addr,socklen_t addrlen); // 开始监听 socket,适用于TCP、服务器 int listen(int sockfd, int backlog); // 接收客户端的连接请求,适用于TCP、服务器 int accept(int sockfd,struct sockaddr* addr,socklen_t* addrlen); // 向服务器发起连接,适用于TCP、客户端 int connect(int sockfd,const struct sockaddr* addr,socklen_t addrlen);我们要知道网络通信的本质是进程间的通信。之前学习的 system V 用于本地进程间通信而后面将要学习的 POSIX 标准既可以用于网络通信也可以用于进程间通信。socket会有很多的种类以便于满足不同的应用场景既有网络socket也有本地socket所以socket的接口会有会有不同的通信接口规范但是socket的设计者只想提供一种通信接口规范如图解释如果我们想进行IPv4网络通信就要使用struct sockaddr_in结构并将其中的地址类型sin_family设置为AF_INET如果想进行本地Socket通信也就是Unix域套接字通信就要使用struct sockaddr_un结构并将其中的地址类型sun_family设置为AF_UNIX。当我们调用bind()、connect()等接口时系统会根据地址结构开头的地址类型判断当前进行的是IPv4网络通信还是本地通信。其原理可以简单理解为如果通用地址结构中的sa_family等于AF_INET系统就按照sockaddr_in结构解析如果等于AF_UNIX系统就按照sockaddr_un结构解析。但是这些接口接收的参数统一都是struct sockaddr*类型而我们实际使用的是struct sockaddr_in*或struct sockaddr_un*。解决方法很简单调用接口时将实际地址结构的指针强制转换成struct sockaddr*即可。这个强制转换不会改变原来的数据只是让接口能够通过统一的指针类型接收不同的Socket地址结构。总结本篇介绍了端口号、TCP与UDP、网络字节序以及Socket编程接口。端口号用于标识主机上的网络通信端点TCP和UDP提供不同的传输方式网络字节序保证不同主机能够正确解析数据Socket则为网络通信和本地通信提供了一套统一的编程接口。
返回列表