当前位置: 首页 > news >正文

深入了解linux网络—— 网络编程基础

IP地址与端口号

了解了IP地址,在网络中用来表示主机的唯一性;

数据报文由源主机通过网络传输到目标主机后,目的主机拿到这个数据报文要如何处理呢?

我们使用QQ聊天、浏览器浏览网页,是如何获取消息的呢?

QQ和浏览器都是进程,也就是说只有将数据交给进程,我们才能看到这些信息。

在这里插入图片描述

在操作系统中存在非常多的进程,拿到的数据报文要交给哪一个进程呢?

IP地址用来标识主机的唯一性,有了IP地址才能够找到唯一的主机;

那也就势必要存在用来标识主机(操作系统)中唯一进程的标识 ——— 端口号

而在操作系统中存在非常多的进程,并不是每一个进程都要从网络中获取信息,那也就是说不是每一个进程都要有端口号。

在操作系统中要从网络中获取信息的进程才拥有唯一的端口号;

也就是说,端口号可以标识主机(操作系统)中唯一的网络进程。

端口号

  1. 端口号是一个2字节,16bit位的整数;
  2. 端口号用来标识一个进程;
  3. IP地址 + 端口号就能够标识网络上的某一台主机的某一个进程;
  4. 一个端口号只能够被一个进程使用。

端口号范围

0-1023:知名端口号,HTTPFTPSSH等广为使用的应用层协议,它们端口号都是固定的;

1024-65535:操作系统动态分配的端口号;客户端程序的端口号,就是由操作系统从该范围内分配的。

端口号与进程ID

学习过操作系统,我们知道,在操作系统中pid可以用来标识唯一进程;这里的端口号也可以用来标识操作系统中的唯一进程;

进程ID属于系统的概念,也可以用来标识唯一进程;但是并没有使用进程ID来作为这里标识唯一进程的标识符;(如果使用进程ID作为这里的标识符,会让系统进程管理和网络强耦合)

此外:一个进程可以绑定多个端口号,一个端口只能绑定一个进程

源IP / 端口号和目的IP / 端口号

传输层协议(TCPUDP)的数据段中存在两个概念:源IP/端口号、目的IP/端口号;

简单来说源IP/端口号表示的是谁发的、目的IP/端口号表示发给谁的。

TCP/UDP编程中会遇到这两个概念。

socket 编程基础

1. socket套接字

了解了IP 和端口号,我们知道IP 可以标识网络中的唯一主机;端口号可以表示主机中的唯一进程。

所以,IP+端口号就可以标识网络中的唯一进程。

所以,只要知道srcipsrcport(源IP和源端口号);detipdstport(目的IP和目的端口号)就可以标识网络中唯二的两个进程。

而网络通信的本质就是:进程间通信

套接字socket : ip + port

2. 传输层协议

了解操作系统,了解了网络协议栈,我们知道,传输层是属于操作系统内核的,那我们要通过网络协议栈进行通信,就势必要调用传输层通过的系统调用。

传输层协议主要有两种:TCP协议和UDP协议

TCP协议

  1. 有连接:在进行通信之前,通信双方必须先建立连接。
  2. 可靠传输:TCP协议能够保证数据有序、完整、无差错从发送方传到接收方。
  3. 面向字节流

UDP协议

  1. 无连接
  2. 不可靠
  3. 面向数据报

这里简单了解一个TCPUDP协议,后序再深入研究。

3. 网络字节序

在之前学习C语言时,曾了解到内存中的多字节数据相对于内存地址有大端和小端之分;

小端存储: 数据的低位字节存储在内存的低地址处;高位字节存储在内存的高地址处。

大端存储:数据的低位字节存储在内存的高地址处;高位字节存储在内存的低地址处。

磁盘文件的多字节数据相对于文件中的偏移地址也有大端小端之分。

那通过网络通信的主机中,既有大端存储、也有小端存储。

那网络是不是要统一规定存储呢?

TCP/IP协议规定,网络数据流应采用大端字节序。即高字节低地址

所以,在将数据传输到网络前,要先进行字节序的转换(主机字节序 -> 网络字节序);如果当前主机是小端机,就要将数据先转换为大端,再传输到网络;如果当前主机是大端机,就可以直接传输到网络。

当然,字节序的转换不需要我们自己去实现;我们可以直接调用库函数,做主机字节序和网络字节序的转换

#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

htonl:32位主机字节序 --> 32位网络字节序

htons:16位主机字节序 --> 16位网络字节序

ntohl:32位网络字节序 --> 32位主机字节序

ntohs:16位网络字节序 --> 16位主机字节序

如果当前主机是大端存储,这些函数就什么都不做,然后返回;

如果当前主机是小端存储,这些函数就会将参数转为对应的大小端,然后返回。

4. socket相关接口

socket常用接口:

//创建套接字socket(文件描述符)
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的接口,在后续编程中详细学习。

上述就是socket常用的接口,有TCP也有UDP相关的。

我们可以发现,这些接口的绝大部分都存在struct sockaddr*的参数,那这个struct sockaddr是什么呢?

在操作系统中,除了struct sockaddr还存在struct sockaddr_instruct sockaddr_un三种结构;

在这里插入图片描述

这三种结构,第一个字段都是16位地址类型,其中struct sockaddr_in的该字段是AF_INET表示网络通信;struct sockaddr_un的该字段是AF_UNIX表示本地通信。

struct sockaddr_in还存在两个字段:

  • 16位(2字节)端口号
  • 32位(4字节)IP地址

struct sockaddr_un用来进行本地通信,其原理类似于system V的命名管道通信。

其另外一个字段是108字节的文件名。

这里主要了解struct sockaddr_in,网络通信(也可以进行被本地通信)

struct sockaddr_in<netinet/in.h>的头文件下。

struct sockaddr_in{__SOCKADDR_COMMON (sin_);in_port_t sin_port;			/* Port number.  */struct in_addr sin_addr;		/* Internet address.  *//* Pad to size of `struct sockaddr'.  */unsigned char sin_zero[sizeof (struct sockaddr)- __SOCKADDR_COMMON_SIZE- sizeof (in_port_t)- sizeof (struct in_addr)];};
  • sin_port指的就是端口号,其类型是in_port_t也就是uint16_t
  • struct in_addr sin_addr,表示的是IP地址;struct in_addr就是对in_addr_t的封装,而in_addr就是uint32_t
struct in_addr{in_addr_t s_addr;};

struct sockaddr_in结构中,看到了IP地址(sin_addr)、也看到了端口号(sin_port);

那第一个标志字段呢?

其标志字段就是__SOCKADDR_COMMON (sin_);

这是一个宏定义:

#define	__SOCKADDR_COMMON(sa_prefix) \
sa_family_t sa_prefix##family

这个宏定义的作用就是:将传进来的字段加上family后缀,在struct sockaddr_in中进行宏替换过后就变成了sin_family(也就是标志字段)

除此之外,在struct sockaddr_in中还存在一个字段,其作用就是填充struct sockaddr_in的大小。
在这里插入图片描述

了解了struct sockaddr_in,但是socket相关接口其中的参数是struct sockaddr*啊,那在调用时该如何调用呢?

这里struct sockaddrstruct sockaddr_instruct sockaddr_un中,第一个字段都是16位地址类型,也就是标志位;

所以,在调用时传参时只需要进行强制类型转换,在函数内部就可以通过第一个字段就可以判断出传进来的是struct sockaddr_in还是struct sockaddr_un;再分别执行不同的代码。

所以,这里struct sockaddrstruct sockaddr_instruct sockaddr_un就像继承关系一样;

sockaddr是基类,sockaddr_insockaddr_un是派生类

在这里插入图片描述

通过第一个字段16位地址类型来判断是struct sockaddr_in还是struct sockaddr_un

本篇文章到这里就结束了,感谢支持
我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=2oul0hvapjsws

http://www.dtcms.com/a/398563.html

相关文章:

  • 焦作做网站哪家好提供微网站制作电话
  • 【嘉力创】天线阻抗设计
  • xlsx-js-style 操作 Excel 文件样式
  • 岛屿数量(广搜)
  • 美食网站要怎么做一个网站交互怎么做的
  • AppInventor2 使用 SQLite(二)导入外部库文件
  • AppGallery Connect(Harmony0S 5及以上)--公开测试流程
  • 深入解析:使用递归计算整数幂的C语言实现
  • 虚幻引擎入门教程开关门
  • 设计模式-组合模式详解
  • 什么是B域?
  • Android 用java程序模拟binder buffer的分配释放以及buffer的向前和向后合并
  • 专门做护肤品网站浙江立鹏建设有限公司网站
  • 电商会学着做网站呢设计师接单渠道
  • Postman 学习笔记 II:测试、断言与变量管理
  • electron设置默认应用程序
  • Flink 初体验10 分钟完成下载、安装、本地集群启动与示例作业运行
  • toLua[二] Examples 01_HelloWorld分析
  • asp源码打开网站网站页面数量
  • 安卓手机termux安装ubuntu被kill进程解决
  • java后端工程师进修ing(研一版‖day48)
  • 目标检测进化史
  • 北京做养生SPA的网站建设高端网站建设 来磐石网络
  • 网站建设有哪三部来年做那些网站能致富
  • 外贸公司网站素材产品营销文案
  • VSCode C/C++ 开发环境配置
  • FPGA自学笔记--VIVADO RAM IP核控制和使用
  • 电源——设计DCDC原理图与参数选型
  • 企业网站建设策划书 前言263云通信官方网站
  • pip config list输出为空?如何配置pip镜像源?不同方式配置有什么区别?