首页 教程 开发工具 【网络】网络基础知识(协议、mac、ip、套接字)

【网络】网络基础知识(协议、mac、ip、套接字)

文章目录

  • 1. 计算机网络的背景
  • 2. 认识网络协议
    • 2.1 协议分层
    • 2.2 OS与网络的关系
  • 3. 网络传输基本流程
    • 3.1 局域网通信流程
    • 3.2 跨网络通信流程
  • 4. Socket 编程预备
    • 4.1 理解源IP地址和目的IP地址
    • 4.2 端口号与Socket
    • 4.3传输层的典型代表
    • 4.4 网络字节序
  • 5. socket 编程接口
    • 5.1 介绍
    • 5.2 案例演示

【网络】网络基础知识(协议、mac、ip、套接字)

1. 计算机网络的背景

【网络】网络基础知识(协议、mac、ip、套接字)
所谓的 “局域网” 和 “广域网” 只是一个相对的概念。

2. 认识网络协议

我们都知道,协议就是“双方”都必须遵守的约定。

那什么叫网络协议呢?

计算机生产厂商有很多,计算机操作系统也有很多,计算机网络硬件设备还是有很多。
如何让这些不同厂商之间生产的计算机能够相互顺畅的通信呢?就需要有人站出来,约定一个共同的标准,大家都来遵守,这就是网络协议

无论是电脑、手机还是其他设备,只要它们遵循相同的网络协议,就能在网络上互相通信、交换数据。

2.1 协议分层

协议本质也是软件,在设计上为了更好的进行模块化、解耦合,也是被设计成为层状结构的。

在现实生活中,我们可以通过电话直接和朋友交流,因此我们认为“同层协议可以直接通信”;但本质上,同层协议之间没有直接通信,而是各自使用下层结构的能力,完成通信的,我们本质上是在对电话讲话。

【网络】网络基础知识(协议、mac、ip、套接字)

通过上图我们发现,任何一层的变化,只要遵守协议,都不会影响其它层,所以分层可以实现解耦合,让软件维护的成本更低。

  1. OSI的七层模型

【网络】网络基础知识(协议、mac、ip、套接字)
很多书中都讲了7层不好,其实在网络角度, OSI 定的协议7层模型其实非常完善,但是在实际操作的过程中,会话层、表示层是不可能接入到操作系统中的所以在工程实践中,最终落地的是 5 层协议。

  1. TCP/IP 五层(或四层)模型

TCP/IP 是一组协议的代名词,它还包括许多协议,组成了 TCP/IP 协议族。
【网络】网络基础知识(协议、mac、ip、套接字)

TCP/IP 通讯协议采用了 5 层的层级结构, 每一层都呼叫它的下一层所提供的网络来完成自己的需求。

  • 物理层:负责光/电信号的传递方式。比如现在以太网通用的网线(双绞 线)、 早 期以太网采用的的同轴电缆(现在主要用于有线电视)、 光纤,现在的 wifi 无线网使用 电磁波等都属于物理层的概念。 物理层的能力决定了最大传输速率、 传输距离、 抗 干扰性等。集线器(Hub)工作在物理层。
  • 数据链路层: 负责设备之间的数据帧的传送和识别。例如网卡设备的驱动、帧同步(就是说从网线上检测到什么信号算作新帧的开始)、 冲突检测(如果检测到冲突就 自动重发)、数据差错校验等工作。有以太网、令牌环网、无线 LAN 等标准。 交换机 (Switch)工作在数据链路层.
  • 网络层: 负责地址管理和路由选择。 例如在 IP 协议中, 通过IP 地址来标识一台 主机,,并通过路由表的方式规划出两台主机之间的数据传输的线路(路由)。路由器 (Router)工作在网路层.
  • 传输层: 负责两台主机之间的数据传输。如传输控制协议 (TCP), 能够确保数据 可靠的从源主机发送到目标主机.
  • 应用层: 负责应用程序间沟通, 如简单电子邮件传输(SMTP)、文件传输协 议(FTP)、 网络远程访问协议(Telnet) 等.

网络编程主要就是针对应用层

物理层我们考虑的比较少, 我们只考虑软件相关的内容,因此很多时候我们直接称为TCP/IP 四层模型。

  • 对于一台主机,它的操作系统内核实现了从传输层到物理层的内容
  • 对于一台路由器,它实现了从网络层到物理层
  • 对于一台交换机,它实现了从数据链路层到物理层
  • 对于集线器,它只实现了物理层

但是并不绝对,很多交换机也实现了网络层的转发;很多路由器也实现了部分传输层的内容(比如端口转发)。

  1. 重新理解协议

上面的内容,我们只是懂了一些基本概念,还是达不到我们的目标,下面我们再次重新理解协议和协议分层:

那么为什么要有 TCP/IP 协议?

  • 首先,即便是单机,你的计算机内部,其实都是存在协议的,比如:其他设备和内存通信,会有内存协议。 其他设备和磁盘通信,会有磁盘相关的协议,比如:SATA, IDE, SCSI 等。 只不过我们感知不到罢了。 而且这些协议都在本地主机各自的硬件中,通信的成本、问题比较少。
  • 其次,网络通信最大的特点就是主机之间变远了。 任何通信特征的变化,一定会带来新的问题,有问题就得解决问题,所以需要新的协议。

所以,协议产生的本质就是:解决因距离变远而产生的通信问题。
【网络】网络基础知识(协议、mac、ip、套接字)
由于距离变远产生的问题多种多样,所以要将它们分类,即协议要分层。

2.2 OS与网络的关系

我们都清楚的知道,操作系统各式各样,没有标准,但是为什么不同的操作系统间能够通信呢?

那是因为不同的操作系统中,网络协议栈必须按照TCP/IP协议标准来实现,即不同操作系统使用的网络协议栈一样,那就可以通信了。
【网络】网络基础知识(协议、mac、ip、套接字)

所以,操作系统与网络的关系是:操作系统内要实现网络相关的功能,即网络是操作系统的一个模块

那么到底什么是协议呢?

既然操作系统要实现网络的功能,那OS内就会存在大量的协议,OS就要管理协议,所以协议本质就是数据结构,即结构体
【网络】网络基础知识(协议、mac、ip、套接字)

问题: 主机 B 能识别 data, 并且准确提取 a=10, b=20, c=30 吗? 回答: 答案是肯定的!
因为双方都有同样的结构体类型 struct protocol。 也就是说,用同样的代码实现协议,用同样的自定义数据类型,天然就具有”共识“, 能够识别对方发来的数据,这不就是约定吗?

关于协议的朴素理解: 所谓协议, 就是通信双方都认识的结构化的数据类型(结构体)

3. 网络传输基本流程

3.1 局域网通信流程

首先,两台主机在同一个局域网,是否能够直接通信? - - 是的,一台主机发送的信息,在同一个局域网下的所有主机,都可以收到。

只不过在局域网上的每台主机,要有唯一的标识来保证主机的唯一性: mac 地址。

mac地址长度为 48 位,即 6 个字节。一般用 16 进制数字加上冒号的形式来表示(例如:08:00:27:03:fb:19), 在网卡出厂时就确定了,不能修改,mac 地址通常是唯一的。

【网络】网络基础知识(协议、mac、ip、套接字)

以太网中,任何时刻,只允许一台机器向网络中发送数据

  • 如果有多台同时发送, 会发生数据干扰, 我们称之为数据碰撞

所以,以太网就是临界资源,是互斥访问的,但是不加锁,先用,碰撞出错了再说。

  • 所有发送数据的主机要进行碰撞检测碰撞避免(以保证数据读写的原子性)
  • 没有交换机的情况下,一个以太网就是一个碰撞域
  • 局域网通信的过程中,主机对收到的报文确认是否是发给自己的,是通过目标mac地址在数据链路层判定的,若不是,直接丢弃,上层用户感知不到。

在数据传输时,要经过每一层;其中每层都有协议,所以当我进行数据传输流程的时候,要进行封装和解包
【网络】网络基础知识(协议、mac、ip、套接字)
报头部分(对应协议层的结构体字段)我们一般叫做报头;除了报头 剩下的叫做有效载荷,故报文 = 报头 + 有效载荷。

我们在明确一下不同层的完整报文的叫法,不同的协议层对数据包有不同的称谓

  • 在传输层叫做段(segment),
  • 在网络层叫做数据报 (datagram),
  • 在链路层叫做帧(frame).
  • 应用层数据通过协议栈发到网络上时,每层协议都要加上一个数据首部,称为封装。
    • 首部信息中包含了一些类似于首部有多长,载荷有多长,上层协议是什么等信息。
    • 数据封装成帧后发到传输介质上,到达目的主机后每层协议再剥掉相应的首部,根据首部中的 “上层协议字段” 将数据交给对应的上层协议处理。

从今天开始, 我们学习任何协议, 都要先宏观上建立这样的认识:

  1. 要学习的协议,是如何做到解包的? 只有明确了解包, 封包也就能理解
  2. 要学习的协议,是如何做到将自己的有效载荷, 交付给上层协议的?

3.2 跨网络通信流程

IP 地址是在 IP 协议中,用来标识网络中不同主机的地址。

  • 对于 IPv4 来说, IP 地址是一个 4 字节,32 位的整数;
  • 我们通常也使用 “点分十进制” 的字符串表示 IP 地址,例如 192.168.0.1;用点分割的每一个数字表示一个字节,范围是 0 - 255;

可是,你们又没有一个疑问:上面我们所说的mac地址也能唯一标识一个主机,但二者有什么区别呢?

【网络】网络基础知识(协议、mac、ip、套接字)
唐僧每经过一个城池,都会询问国王下一个地方它去哪,它给国王说的是:我从长安来,到西天去。
国王根据唐僧的目的地,告诉唐僧距离当前位置最近的下一个城池。

所以:

  • IP地址是最终目标,用来标识整个网络中标识唯一性。
  • MAC地址是近期目标,用来标识主机在局域网中的唯一性。其受IP地址影响,根据路由器完成mac地址的切换(mac地址仅在局域网中有效)

跨网段的主机的数据传输,数据从一台计算机到另一台计算机传输过程中要经过一个或多个路由器。
【网络】网络基础知识(协议、mac、ip、套接字)
为什么要去目标主机, 先要走路由器?
【网络】网络基础知识(协议、mac、ip、套接字)
结合封装与解包,体现路由器解包和重新封装的特点
【网络】网络基础知识(协议、mac、ip、套接字)
提炼 IP 网络的意义和网络通信的宏观流程

【网络】网络基础知识(协议、mac、ip、套接字)

所以,IP网络层存在的意义:提供网络虚拟层,让世界的所有网络都是IP网络,屏蔽最底层网络的差异。

4. Socket 编程预备

4.1 理解源IP地址和目的IP地址

IP 在网络中,是用来标识主机的唯一性的,可以通过IP传输数据。

但是这里要思考一个问题: 数据传输到主机是目的吗? 不是的,因为数据是给人用的。

  • 比如: 聊天是人在聊天,下载是人在下载,浏览网页是人在浏览?
  • 但是人是怎么看到聊天信息的呢? 怎么执行下载任务呢? 怎么浏览网页信息呢?通过启动的 qq,迅雷,浏览器。
  • 而启动的 qq,迅雷,浏览器都是进程。 换句话说,进程是人在系统中的代表,只要把数据给进程,人就相当于就拿到了数据。
    【网络】网络基础知识(协议、mac、ip、套接字)

所以: 数据传输到主机不是目的,而是手段。 到达主机内部,再交给主机内的进程,才是目的

那么,源IP地址和目的IP地址是干什么的呢?- - 解决两端主机的唯一性

但是系统(主机)中,同时会存在非常多的进程, 当数据到达目标主机之后,怎么转发给目标进程呢?

4.2 端口号与Socket

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

  • 端口号是一个2字节16 位的整数
  • 端口号用来标识一个进程,告诉操作系统,当前的这个数据要交给哪一个进程来处理
  • 一个端口号只能被一个进程占用

端口号范围划分

  • 0 - 1023:知名端口号, HTTP、FTP、SSH 等这些广为使用的应用层协议,他们的端口号都是固定的。
  • 1024 - 65535:操作系统动态分配的端口号,客户端程序的端口号就是由操作系统从这个范围分配的

我们之前在学习系统编程的时候,学习了 pid 表示唯一一个进程;此处我们的端口号也是唯一表示一个进程,那么这两者之间是怎样的关系?

  • 进程 PID 属于系统概念,技术上也具有唯一性,确实可以用来标识唯一的一个进程, 但是这样做, 会让系统进程管理和网络强耦合,实际设计的时候, 并没有选择这样做。
  • 另外,一个进程可以绑定多个端口号, 但是一个端口号不能被多个进程绑定

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

那么, IP 地址 + 端口号就能够标识网络上的某一台主机的某一个进程,所以网络通信的本质是:进程间通信,网络就是它们看到的同一份资源,我们把IP 地址 + 端口号叫做Socket(套接字)

4.3传输层的典型代表

如果我们了解了系统,也了解了网络协议栈,我们就会清楚,传输层是属于内核的,那么我们要通过网络协议栈进行通信,必定调用的是传输层提供的系统调用,来进行的网络通信。
【网络】网络基础知识(协议、mac、ip、套接字)

认识 TCP 协议,此处我们先对 TCP(Transmission Control Protocol 传输控制协议)有一个直观的认识

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

认识 UDP 协议,此处我们也是对 UDP(User Datagram Protocol 用户数据报协议)有一个直观的认识;

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

4.4 网络字节序

我们知道,内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分,大端与小端机器通信,要怎么办呢

【网络】网络基础知识(协议、mac、ip、套接字)所以,必须在网络中将大小端规定好!

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

因此,网络规定:所有发送到网络上的数据,都必须是大端的

为使网络程序具有可移植性,使同样的 C 代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。
【网络】网络基础知识(协议、mac、ip、套接字)

这些函数名很好记,h表示host,n表示network,l 表示32位长整数(常用来转ip),s表示16位短整数(常用来转port)。

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

5. socket 编程接口

5.1 介绍

// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器) intsocket(int domain,int type,int protocol);// 绑定端口号 (TCP/UDP, 服务器)intbind(int socket,conststructsockaddr*address, socklen_t address_len);// 开始监听 socket (TCP, 服务器) intlisten(int socket,int backlog);// 接收请求 (TCP, 服务器)intaccept(int socket,structsockaddr* address, socklen_t* address_len);// 建立连接 (TCP, 客户端)intconnect(int sockfd,conststructsockaddr*addr, socklen_t addrlen);

在上述接口中,很多都有一个 sockaddr 的结构体,这是因为套接字的种类有很多:网络socket、本地socket(域间socket)、原始socket。

OS为了提供一个统一的系统调用接口,设计了sockaddr 的结构体
【网络】网络基础知识(协议、mac、ip、套接字)
用户具体使用什么类型的socket不管,只要你传进来的指针是sockaddr类型的;OS内部为了区分是网络还是本地,在这三个结构中,大家的前两个字节用来标识地址的类型 (这在C++中不就是继承与多态嘛)

5.2 案例演示

下面使用一个简单的回显服务器和客户端代码,演示一些UDP中常用的接口

服务器端:

  1. 创建套接字

【网络】网络基础知识(协议、mac、ip、套接字)
该系统调用的返回值是一个文件描述符,所以创建socket本质是创建了一个文件。

// 1. 创建UDP网络socketint _socket =::socket(AF_INET, SOCK_DGRAM,0);

  1. 绑定端口号

在绑定socket之前,应初始化一下socket;但在上面我们说了,socket的种类很多,我们这里使用网络socket为例,所以应该先创建一个sockaddr_in类型的socket。
【网络】网络基础知识(协议、mac、ip、套接字)
在初始化sockaddr_in之前,需要注意port与IP的网络字节序问题

【网络】网络基础知识(协议、mac、ip、套接字)

structsockaddr_in inetSocket;bzero(&inetSocket,sizeof(inetSocket));//sockaddr_in全部清零,也可用memset inetSocket.sin_family = AF_INET; inetSocket.sin_port =::htons(_port);//端口-->网络字节序 inetSocket.sin_addr.s_addr =::inet_addr(_ip.c_str());//string -->4字节-->网络字节序

绑定

【网络】网络基础知识(协议、mac、ip、套接字)

// 3. 设置套接字进入内核int n =::bind(_socket,(sockaddr*)&inetSocket,sizeof(inetSocket));

  1. 接收信息

【网络】网络基础知识(协议、mac、ip、套接字)

structsockaddr_in fromUser; socklen_t len =sizeof(fromUser);char buffer[1024];int n =::recvfrom(_socket,&buffer,sizeof(buffer),0,(sockaddr*)(&fromUser),&len);

  1. 发送信息给指定socket

【网络】网络基础知识(协议、mac、ip、套接字)

::sendto(_socket,echoString.c_str(),echoString.size(),0,(sockaddr*)(&fromUser),len);

Server完整代码:

//Common.hpp#pragmaonce#include<stdlib.h>//exit#defineDie(code)\do\{\exit(code);\}while(0)#defineCONVERSE(src)(structsockaddr*)(src)enumexitCode{ SOCKET_ERR =1, BIND_ERR };

#pragmaonce#include<memory>#include<string>#include<cstring>#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#include"Log.hpp"#include"Common.hpp"conststaticint g_socket =-1;conststaticint g_port =8080;conststatic std::string g_default_ip ="127.0.0.1";usingnamespace MyLogModule;classUdpServer{public:UdpServer(uint16_t port = g_port, std::string ip = g_default_ip):_socket(g_socket),_port(port),_ip(ip),_isRunning(false){}~UdpServer(){}voidInit(){// 1. 创建网络socket _socket =::socket(AF_INET, SOCK_DGRAM,0);if(_socket ==-1){LOG(FATAL)<<"socket create fail";Die(SOCKET_ERR);}LOG(NORMAL)<<"file fd:"<< _socket;// 2. 向套接字中填充网络信息structsockaddr_in inetSocket;bzero(&inetSocket,sizeof(inetSocket));// sockaddr_in全部清零,也可用memset inetSocket.sin_family = AF_INET; inetSocket.sin_port =::htons(_port);// 端口-->网络字节序 inetSocket.sin_addr.s_addr =::inet_addr(_ip.c_str());// string -->4字节-->网络字节序// 3. 设置套接字进入内核int n =::bind(_socket,CONVERSE(&inetSocket),sizeof(inetSocket));if(n ==-1){LOG(FATAL)<<"bind fail";Die(BIND_ERR);}LOG(NORMAL)<<"bind success";}voidStart(){if(!_isRunning){ _isRunning =true;while(true){structsockaddr_in fromUser; socklen_t len =sizeof(fromUser);char buffer[1024];int n =::recvfrom(_socket,&buffer,sizeof(buffer),0,CONVERSE(&fromUser),&len);if(n >0){ buffer[n]=0;// 接收成功,显示消息内容,谁发来的uint16_t clientPort =::ntohs(fromUser.sin_port);// 网络字节序-->端口 std::string clientIp =::inet_ntoa(fromUser.sin_addr);// 网络字节序-->4字节-->字符串 std::string message = std::to_string(clientPort)+":"+ clientIp +"#:"; message += buffer;LOG(DEBUG)<< message; std::string echoString ="echo say#"; echoString += buffer;// 将消息在回显给发送方::sendto(_socket, echoString.c_str(), echoString.size(),0,CONVERSE(&fromUser), len);}}} _isRunning =false;}private:int _socket;int16_t _port;// 端口 std::string _ip;// ip地址bool _isRunning;};

客户端

#ifndef__UpdClient__hpp__#define__UpdClient__hpp__#include<sys/socket.h>#include<sys/types.h>#include<netinet/in.h>#include<arpa/inet.h>#include"Log.hpp"#include<memory>#include<string>usingnamespace MyLogModule;classUdpClient{public:UdpClient(std::string ip, std::string port){ _port =stoi(port.c_str()); _ip = ip;}~UdpClient(){}voidStart(){ _socket =::socket(AF_INET, SOCK_DGRAM,0);if(_socket ==-1){LOG(FATAL)<<"socket create fail";Die(SOCKET_ERR);}// 转换为网络字节序,并设置structsockaddr_in server; server.sin_family = AF_INET; server.sin_addr.s_addr =::inet_addr(_ip.c_str()); server.sin_port =::htons(_port);while(true){ std::string message; std::cout <<"Please enter# "; std::getline(std::cin,message);//客户端也要有自己的ip和port,但不需要绑定,因为OS会自动bind//服务端要显示的bind,是因为服务器的端口号,必须稳定!必须是众所周知且不能改变轻易改变的!::sendto(_socket,message.c_str(),message.size(),0,CONVERSE(&server),sizeof(server));char buffer[1024];//虽然上面已经有了sockaddr_in server,但是可能不只有一个服务器哦structsockaddr_in tmp; socklen_t len =sizeof(tmp);int n =::recvfrom(_socket,buffer,sizeof(buffer)-1,0,CONVERSE(&tmp),&len);if(n >0){ buffer[n]=0;//打印服务器回写的 std::cout << buffer << std::endl;}}}private:int _socket;uint16_t _port; std::string _ip;};#endif

clientMain.cc

#include"Common.hpp"#include"UdpClient.hpp"intmain(int argc,char* argv[]){if(argc !=3){ std::cerr <<"usage fail "<<"Usage:"<< argv[0]<<"serverIp serverPort"<< std::endl;Die(USE_ERR);}//使用ip与port构建UdpClient对象的指针 std::shared_ptr<UdpClient> c_ptr = std::make_shared<UdpClient>(argv[1],argv[2]); c_ptr->Start();return0;}

至此,两主机就可完成网络通信了。

【网络】网络基础知识(协议、mac、ip、套接字)

查看网络服务是否启动的命令:netstat

【网络】网络基础知识(协议、mac、ip、套接字)

  • u:udp
  • a: all
  • p:pid/program
  • n:num(能显示成数字的则显示)

但是当前的程序还有一个问题,那就是如果服务器上有多张网卡,那就有多个ip地址,但是server默认的ip是127.0.0.1,这样就会导致server无法收到其它ip所搜到的信息。

因此,需要将server的ip设置为INMADDR_ANY

【网络】网络基础知识(协议、mac、ip、套接字)
将server中涉及ip的位置都修改就可以了

【网络】网络基础知识(协议、mac、ip、套接字)

但是上面的代码还有点不优雅,特别是涉及ip地址与端口号那里,下面我们修改一下,直接将ip与port封装成一个对象。

#pragmaonce#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#include<string>#include"Common.hpp"classInetAddr{private:voidportNet2Host(){ _port =::ntohs(_net_addr.sin_port);}voidipNet2Host(){// 此种方式inbuffer是局部的,不会造成问题char inbuff[64]; _ip =::inet_ntop(AF_INET,&_net_addr.sin_addr, inbuff,sizeof(inbuff));}public:InetAddr(){}InetAddr(conststructsockaddr_in&addr):_net_addr(addr){portNet2Host();ipNet2Host();}// 供服务端创建自己的InetAddr(uint16_t port):_port(port),_ip(""){ _net_addr.sin_family = AF_INET; _net_addr.sin_port =::htons(_port); _net_addr.sin_addr.s_addr = INADDR_ANY;}structsockaddr*Getaddr(){returnCONVERSE(&_net_addr);} socklen_t Getlen(){returnsizeof(_net_addr);}uint16_tgetPort(){return _port;} std::string getIP(){return _ip;}structsockaddr_ingetAddr(){return _net_addr;}~InetAddr(){}private:structsockaddr_in _net_addr;uint16_t _port; std::string _ip;};

【网络】网络基础知识(协议、mac、ip、套接字)
效果:
【网络】网络基础知识(协议、mac、ip、套接字)


TCP接口介绍:

// 绑定端口号 (TCP/UDP, 服务器)intbind(int socket,conststructsockaddr*address, socklen_t address_len);// 开始监听 socket (TCP, 服务器) intlisten(int socket,int backlog);// 接收请求 (TCP, 服务器)intaccept(int socket,structsockaddr* address, socklen_t* address_len);// 建立连接 (TCP, 客户端)intconnect(int sockfd,conststructsockaddr*addr, socklen_t addrlen);

listen:函数的第二个参数,表示最多允许有 backlog 个客户端处于连接等待状态,如果接收到更多的连接请求就忽略,这里设置不会太大。

【网络】网络基础知识(协议、mac、ip、套接字)

accept:

【网络】网络基础知识(协议、mac、ip、套接字)

与UDP不同的是:tcp没有recvfrom与sendto方法,它直接使用read 和write;

【网络】网络基础知识(协议、mac、ip、套接字)

connect

  • 客户端需要调用 connect()连接服务器;
  • connect 和 bind 的参数形式一致,区别在于 bind 的参数是自己的地址, 而connect 的参数是对方的地址

【网络】网络基础知识(协议、mac、ip、套接字)
【网络】网络基础知识(协议、mac、ip、套接字)

评论(0)条

提示:请勿发布广告垃圾评论,否则封号处理!!

    猜你喜欢
    【MySQL】用户管理

    【MySQL】用户管理

     服务器/数据库  2个月前  2.18k

    我们推荐使用普通用户对数据的访问。而root作为管理员可以对普通用户对应的权限进行设置和管理。如给张三和李四这样的普通用户权限设定后。就只能操作给你权限的库了。

    Cursor Rules 让开发效率变成10倍速

    Cursor Rules 让开发效率变成10倍速

     服务器/数据库  2个月前  1.24k

    在AI与编程的交汇点上,awesome-cursorrules项目犹如一座灯塔,指引着开发者们驶向更高效、更智能的编程未来。无论你是经验丰富的老手,还是刚入行的新人,这个项目都能为你的编程之旅增添一抹亮色。这些规则文件就像是你私人定制的AI助手,能够根据你的项目需求和个人偏好,精确地调教AI的行为。突然间,你会发现AI不仅能理解Next.js的最佳实践,还能自动应用TypeScript的类型检查,甚至主动提供Tailwind CSS的类名建议。探索新的应用场景,推动AI辅助编程的边界。

    探索Django 5: 从零开始,打造你的第一个Web应用

    探索Django 5: 从零开始,打造你的第一个Web应用

     服务器/数据库  2个月前  1.16k

    Django 是一个开放源代码的 Web 应用程序框架,由 Python 写成。它遵循 MVT(Model-View-Template)的设计模式,旨在帮助开发者高效地构建复杂且功能丰富的 Web 应用程序。随着每个版本的升级,Django 不断演变,提供更多功能和改进,让开发变得更加便捷。《Django 5 Web应用开发实战》集Django架站基础、项目实践、开发经验于一体,是一本从零基础到精通Django Web企业级开发技术的实战指南《Django 5 Web应用开发实战》内容以。

    MySQL 的mysql_secure_installation安全脚本执行过程介绍

    MySQL 的mysql_secure_installation安全脚本执行过程介绍

     服务器/数据库  2个月前  1.09k

    mysql_secure_installation 是 MySQL 提供的一个安全脚本,用于提高数据库服务器的安全性

    【MySQL基础篇】概述及SQL指令:DDL及DML

    【MySQL基础篇】概述及SQL指令:DDL及DML

     服务器/数据库  2个月前  491

    数据库是长期存储在计算机内的、有组织的、可共享的、统一管理的大量数据的集合。数据库不仅仅是数据的简单堆积,而是遵循一定的规则和模式进行组织和管理的。数据库中的数据可以包括文本、数字、图像、音频等各种类型的信息。

    Redis中的哨兵(Sentinel)

    Redis中的哨兵(Sentinel)

     服务器/数据库  2个月前  316

    ​ 上篇文章我们讲述了Redis中的主从复制(Redis分布式系统中的主从复制-CSDN博客),本篇文章针对主从复制中的问题引出Redis中的哨兵,希望本篇文章会对你有所帮助。