> 作者:დ旧言~
> 座右铭:松树千年终是朽,槿花一日自为荣。> 目标:理解并掌握socket套接字。
> 毒鸡汤:有些事情,总是不明白,所以我不会坚持。早安!
> 专栏选自:网络
> 望小伙伴们点赞👍收藏✨加关注哟💕💕
前面我们已经学习了网络的基础知识,对网络的基本框架已有认识,算是初步认识到网络了,如果上期我们的学习网络是步入基础知识,那么这次学习的板块就是基础知识的实践,我们今天的板块是学习网络重要之一,学习完这个板块对虚幻的网络就不再迷茫,那话不多说进入今天的主题【网络】socket套接字基础知识
学习【网络】网络基础入门咱们按照下面的图解:
IP:
每台主机都有自己的IP地址,所以当数据从一台主机传输到另一台主机就需要IP地址。报头中就会包含源IP和目的IP。
我们把数据从一台主机传递到另一台主机不是真正目的,真正通信的不是这两个机器,其实是这两台机器上面的软件,而这个软便网络的应用层中,我们知道应用层不止一个软件,公网IP标识了一台唯一的主机,那么数据就可以由一台主机传递到另一台主机。但是有这么多的软件(进程),怎么保证软件A发送的被软件B接收呢?也就是说用什么来标识主机上客户或者服务进程的唯一性呢?最好的解释就是下面这段内容:
为了更好的表示一台主机上服务进程的唯一性,用端口号port标识服务进程、客户端进程的唯一性。
端口号:
总结:
两个问题:
标识一个进程有pid,那么为什么还需要端口号port呢?
一个端口号只能被一个进程占用,但是一个进程可以绑定多个端口号?(对)
概念分析:
MAC地址(Media Access Control Address, 局域网地址)在OSI模型的第二层数据链路层发挥作用,标识本地网络上的设备物理地址。
总结分析:
对于处于同一局域网的多台主机,它们直接向局域网发送的数据是被所有主机共享的(包括发送的主机自己),也就相当于广播,但是只有特定的主机才会处理它(虽然所有主机都收到了信息)。这是因为主机发送的数据中包含了指定主机的MAC地址,除此之外,为了校验数据的完整性,还包含了发生数据的主机本身的MAC地址,以供主机在发送信息后再接收校验。其中,发送信息的主机的MAC地址叫做源MAC地址,接收信息的主机的MAC地址叫做目的MAC地址。
在IP与端口号中我们初步了解,这里我们再单独拿出来讲解。
概念分析:
IP地址(Internet Protocol, 互联网协议)在OSI模型的第三层网络层发挥作用,它是一个逻辑地址,用于唯一标识互联网连接设备。
总结分析:
MAC地址标识着设备的全球唯一性,但是仅靠MAC地址无法完成不同网络中数据的传输。我们知道,数据传输是通过网络协议栈传输的,数据自上而下传输时会被每一层协议封装一个报头信息,当数据自下而上传输时,每一层协议会解封装,直到应用层取到数据本身。但是不同的网络可能在某些层的协议有所区别,因此报头的封装和解封装的过程就不像局域网那样对称,因此需要配合IP地址在不同的网络中跳转。
基础概念:
在不同网络中,路由器起着“指路人”的作用,实际上数据在传输过程中可能会经过多个不同网络,那么报头信息中的两个MAC地址一直在随着路由器(路由器也是硬件)的变化而变化,但是源IP地址和目的IP地址不会改变。这就像唐僧每到一个地方都会说“自东土大唐而来,去西天取经”,出发点和目的地是不应该被改变的(在某些特殊情况源IP可能会被改变,但是目的IP绝对不会被改变),但是遇到的好心人听到这句话以后都会告诉唐僧下一个地方应该怎么走,这就是MAC地址和IP地址在不同网络中配合数据传输的过程。
什么是端口号?
总结分析:
结合进程相关知识,数据本身是被运行起来的进程处理的,因此数据通过网络传输到不同主机中只是一个搬运的过程。因此可以认为数据是在不同主机中的不同进程之间传输,也就是网络层面上的进程间通信。端口号的名字很形象,现实中的港口(port)也是类似的。主机中各种不同的进程就好像一个个蓄势待发的货船,它们在不同编号的位置等待货物,一旦货物就绪,一个个进程就会对其处理。
IP地址标识了公网中主机的唯一性,端口号标识主机上进程的唯一性,那么IP地址+端口号就标识了网络上某台主机中的进程的唯一性。和IP地址类似,端口号会在传输层被封装进报头信息中。
既然PID和端口号都能表示主机上进程的唯一性,为什么不用PID进行网络传输?
端口号标识的进程是PID标识的进程的子集,它们标识的范围不同。PID就像每个人的身份证,虽然它能表示我们在这片土地上的唯一性,但是我们很多时候不使用它,而是使用范围合适、便于管理的标识,例如在教室用座位号、在学校用学号、在高考中用准考证和在银行里用身份证等等。使用PID当然可以,但是这样会增加筛选所有进程中的网络服务进程的负担,也会增加其他非网络服务进程的安全风险。这也是一种解耦的做法,单独用一种标识表示特定种类的元素,能省去筛选的成本。
概念分析:
Socket(套接字)是计算机网络中的一个软件结构,它用于在计算机网络中的节点之间发送和接收数据。套接字的结构和属性由网络架构的应用程序编程接口(API)定义。它允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。简单来说,Socket是计算机之间进行通信的一种约定或一种方式。
通俗概念:
Socket这个词在计算机网络中的翻译为“套接字”,原意指的是插座或者插槽。在计算机网络中,它被用来描述两个程序之间建立连接的端点。就像电器插头需要插入插座才能通电一样,两个程序之间也需要一个“插座”来建立连接。因此,这个词被引申为“套接字”。
Socket函数:
Socket函数是应用程序与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部。它将底层复杂的协议体系、执行流程进行了封装,封装完的结果就是一个SOCKET了,也就是说,SOCKET是我们调用协议进行通信的操作接口。
总结分析:
Socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。Socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)。
在实践过程中,其实不必要关心它的各种定义,可以简单地理解为它就是一个数据包,是包含各种通信相关属性的结构体。内置的库中有许多函数,它们会在函数内部对这个数据包中的属性处理。值得注意的是,socket本质是一个按照某种规则(协议)构造出来的一个文件,只要通信两端都按照约定好的规则使用它其中的数据,就能实现通信过程。
TCP概念:
TCP(Transmission Control Protocol,传输控制协议)提供的是面向连接,可靠的字节流服务。即客户和服务器交换数据前,必须现在双方之间建立一个TCP连接,之后才能传输数据。并且提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。
TCP特点:
UDP概念:
UDP(User Datagram Protocol,用户数据报协议)是一个简单的面向数据报的运输层协议。它不提供可靠性,只是把应用程序传给IP层的数据报发送出去,但是不能保证它们能到达目的地。由于UDP在传输数据报前不用再客户和服务器之间建立一个连接,且没有超时重发等机制,所以传输速度很快。
UDP特点:
理解不可靠传输:
为什么UDP不提供可靠性,还要使用它?
尽管UDP不提供可靠性,但它的优点在于传输速度快。由于UDP在传输数据报前不用再客户和服务器之间建立一个连接,且没有超时重发等机制,所以传输速度很快 。这对于一些对实时性要求较高的应用程序来说非常重要,例如在线游戏、实时音视频传输等。在这些情况下,使用UDP协议能够提供更快的响应速度。一般情况下,为了数据安全都使用TCP,在特殊场景下(例如直播和视频)可能会使用UDP。在优秀的通信算法中,常常会同时使用TCP和UDP,根据实际情况调度策略。
高低位:
对于任意一个十进制的数值,它可以用多项式10ⁿ的和表示,例如123 = 1×10² + 2×10¹ + 3×10º字节的高低对应着权值的大小。例如,对于整数0x12345678,0x12是最高位字节,它的权值是16的三次方,0x78是最低位字节,它的权值是16的零次方。
高低地址:
大端和小端:
如何定义网络数据流的地址:
常用转换函数:
#include // 主机序列转网络序列 uint16_t htons(uint16_t hostshort); uint32_t htonl(uint32_t hostlong); // 网络序列转主机序列 uint16_t ntohs(uint16_t netshort); uint32_t ntohl(uint32_t netlong);
命名解读:
- h:host,表示主机字节序;
- n:net,表示网络字节序;
- l:long,表示32位长整数;
- s:short,表示16位短整数。
通常情况下,不论测试机是大端还是小端,为了可移植性都要调用这些函数进行转换,如果机器本身是大端,那么这些函数将直接返回。
TCP是面向连接的,通过socket实现通信的步骤是:
UDP是面向字节流的,它的步骤比较简单:
头文件包含:
#include #include
socket()函数用于创建套接字:
int socket(int domain, int type, int protocol);
参数讲解:
domain(域):指定套接字家族,简单地说就是指定通信的方式是本地还是网络:
- AF_UNIX, AF_LOCAL:本地通信。
- AF_INET:网络通信。
- …
- SOCK_STREAM:面向连接的套接字/流格式套接字。
- SOCK_DGRAM:无连接的套接字/数据报套接字。
0
,常用的有:
- IPPROTO_TCP:表示TCP传输协议。
- IPPTOTO_UDP:表示UDP传输协议。
bind()函数用于将套接字与指定的IP地址和端口号绑定。通常在TCP协议或UDP协议的服务端设置:
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数讲解:
listen() 函数用于将套接字转换为被动监听状态。通常在TCP协议的服务端设置:
int listen(int sockfd, int backlog);
参数讲解:
accept() 函数用于从监听套接字的未完成连接队列中提取第一个连接请求,创建一个新的已连接套接字,并返回一个指向该套接字的文件描述符。通常在TCP协议的服务端设置:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数讲解:
connect() 函数用于建立与指定套接字的连接。通常在TCP协议的服务端设置:
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数讲解:
概念:
套接字是一种通信机制,用于在不同主机或同一主机上的进程间通信。套接字有多种类型,包括流式套接字(SOCK_STREAM)、数据报套接字(SOCK_DGRAM)和原始套接字(SOCK_RAW)等。在这里,我们讨论的是网络套接
域间套接字:
域间套接字(Domain Socket)是一种特殊类型的套接字(socket)。套接字是一种通信机制,用于在不同主机或同一主机上的进程间通信。套接字有多种类型,包括流式套接字(SOCK_STREAM)、数据报套接字(SOCK_DGRAM)和原始套接字(SOCK_RAW)等。域间套接字是其中的一种类型,用于在同一台主机上的进程间通信。
简单来说,域间套接字是套接字的一种类型,它与其他类型的套接字共享相似的API和通信机制,但是它专门用于在同一台主机上的进程间通信。
原始套接字:
网络套接字:
概念:
sockaddr结构并不能很好地表示各种类型的地址,因此通常会使用特定于地址族的结构来表示套接字地址,例如sockaddr_in(用于IPv4地址)和sockaddr_un(用于Unix域地址)。这些结构与sockaddr结构具有相同的大小和对齐方式,可以相互转换。
这个结构体的唯一目的是为了将不同协议族的地址结构体指针转换为一个“通用”类型,以避免编译器警告。例如,对于IPv4协议族的地址结构体sockaddr_in,它的定义如下:
struct sockaddr_in { sa_family_t sin_family; /* AF_INET */ in_port_t sin_port; /* 端口号 */ struct in_addr sin_addr; /* IPv4地址 */ };
今天内容就到这里啦,时间过得很快,大家沉下心来好好学习,会有一定的收获的,大家多多坚持,嘻嘻,成功路上注定孤独,因为坚持的人不多。那请大家举起自己的小手给博主一键三连,有你们的支持是我最大的动力💞💞💞,回见。