网络编程 Linux环境 C语言实现

进程间通信的延续

跨电脑进程间通信


一、远程通信方式

  1. 电路交换------老式有线电话通信

  2. 报文交换

  3. 分组交换

    支持分时机制的(分片机制)报文交换

    ​现行网络大部分都是采用分组交换形式


二、网络&互联网&因特网

网络Network:多台计算机通过某种传输介质连接在一起形成的整体 计算机与计算机相连形成的整体 局域网

互联网internet:网络与网络相连形成的整体

全球拥有很多的互联网,其中一个用户最多、使用范围最广的民用互联网叫因特网(Internet)。

我们主要学习基于因特网这个特殊互联网的通信编程


三、因特网架构

因特网总体有两大部分组成:

  1. 核心网络

    很多个局域网(也被称为子网)通过路由器(分组交换机)交叉相连构成

  2. 边缘网络

    一个边缘网络也是由多个子网通过路由器相连构成,但只有一个路由器与核心网络中的某个路由器相连

核心网上两台主机(计算机)间的传输过程大体如下:

  1. 发送主机的网口 到达 当前子网路由器的某个网口
  2. 源路由器 经过 一系列中间路由器的转发到达 目标子网的路由器
  3. 目标子网路由器的某个网口 到达 目标主机

四、IP地址 & 端口号 & MAC地址

为了完成主机到主机传输,因特网需要给核心网络上的每台主机和路由器指定一个唯一的身份标识,这个身份标识被称为IP地址

为了完成局域网内网口到网口的传输,需要给每张网卡指定一个唯一的身份标识,这个身份标识被称为MAC地址 网卡地址 物理地址

为了完成进程到进程的传输,需要给每台主机上的不同进程一个唯一的身份标识:

  1. 进程身份标识只需确保同一台主机上是不同的即可
  2. 网络中不同主机上运行的操作系统可能相同也可能不同,而不同的操作系统自身对进程进行身份标识的手段是不同的,因此不能使用任何一个操作系统设计的身份标识手段,为了统一起见,因特网使用一套新的标识手段来对进程进行标识,这个标识被称为端口号

MAC地址作为一个常识了解即可,与后续学习密切相关的是IP地址和端口号

因特网中:一个IP地址+一个端口号 = 一个socket地址,用来标识哪台主机上的哪个进程


4.1 IP地址的表示方法

支持三种方式:

  1. 4字节整型 ------ 实际传输过程中使用

  2. 点分十进制字符串形式 例如:"192.168.6.56"

    点分隔的每个数字的取值范围:[0,255]

  3. 域名 例如:"www.baidu.com"

显然域名比点分十进制字符串形式更容易记忆,点分十进制字符串形式比4字节整型更容易记忆

Linux操作系统提供了如下两个函数完成4字节整型 与 点分十进制字符串形式IP地址的相互转换:

域名字符串由三个或四个部分组成,依次为:

  1. 服务名:www----网页服务 ftp----文件传输服务 mailto-----电子邮件服务等等
  2. 组织名:提供服务的公司 或 组织机构名
  3. 组织性质:com-----商业 edu----教育 org-----非盈利性国际组织
  4. 地区名:可选 cn----中国大陆 tw----中国台湾 hk----中国香港

因特网给核心网上的每台主机指定一个或多个域名来代表其对应的IP地址

因特网上有些主机专门提供了域名服务,这些主机管理着一个数据库,数据库中记录了全球所有域名及其对应的ip地址

任何想要根据域名获得IP地址程序,都可以向提供域名服务的主机发送域名解析请求,这些主机会查表向这些程序回馈查询结果

​Linux系统将发送域名解析请求和接收域名解析请求的回应封装在一个函数里:gethostbyname

显然,gethostbyname能够成功完成一次调用的前提:运行该程序的主机必须是处于联网状态

​实际项目中一般只需要使用多个IP地址中的第一个,则对gethostbyname的返回值做如下访问即可:

struct hostent *pret = gethostbyname(.....);

第一个4字节整型IP地址所占空间的名字:**(struct in_addr **)pret->h_addr_list

4.2 端口号

2字节的无符号整型

小于1024的:知名端口号,已与著名的网络服务进程相对应,例如:网页服务进程的默认端口号为80,ftp服务进程的默认端口号为23

大于等于1024的:动态端口号,作为客户端进程、或非著名网络服务进程的端口号

4.3 socket地址

ip地址、端口号是因特网这种互联网对主机和进程的标识手段,其它互联网有着不同的标识手段

因此IP地址、端口号两个概念对其它互联网无效

Linux系统设计的一套用于网络通讯接口,期望能够适用于更多的互联网场合,因此在这些接口中涉及到socket地址类型的参数时设计一个通用的socket地址结构体:struct sockaddr

这些接口的实现代码中会根据第一个成员值而使用与当前互联网对应的专用socket地址结构体,应用程序自身代码中也使用与当前互联网对应的专用socket地址结构体,例如:因特网用 struct sockaddr_in​


五、字节序

所谓字节序endian就是整数在内存中的存放次序,有两种字节序:

  1. 小端字节序little-endian:或 低端字节序 整数的低位从内存的低地址开始存放
  2. 大端字节序big-endian:或 高端字节序 整数的高位从内存的低地址开始存放

一台计算机采用哪种字节序,由组成这台计算机的CPU设计商决定:

  1. Intel X86系列的CPU 采用小端字节序
  2. IBM PowerPC系列的CPU 采用大端字节序
  3. ARM系列处理器默认采用小端,可以通过特殊指令配置成大端

练习:编写一个函数,通过返回值判断当前计算机是小端还是大端

代码:

#include <stdio.h>

int is_little_endian_v1(){
	unsigned int x = 0x12345678;
	unsigned char *puc = (unsigned char *)&x;

	return *puc == 0x78 ? 1 : 0;
}

int is_little_endian_v2(){
	union U{
		unsigned int v1;
		unsigned char v2;
	};
	
	union U u = {0x12345678};
	return u.v2 == 0x78 ? 1 : 0;
}

int main(int argc,char *argv[]){
	if(is_little_endian_v1())    printf("This computer is little endian!!!\n");
	else    printf("This computer is big endian!!!\n");

	return 0;
}

输出:



inet_aton ----- 得到4字节整型IP地址已是网络字节序

测试代码:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <stdio.h>
int main(int argc,char *argv[]){
	struct in_addr addr;
	int ret = 1;
	char *pip = NULL;

	if(argc < 2){
		printf("The argument is too few\n");
		return 1;
	}

	ret = inet_aton(argv[1],&addr);
	if(!ret){
		printf("The IP:%s is invalid\n",argv[1]);
		return 2;
	}

	pip = inet_ntoa(addr);
	printf("The IP is %s\n",pip);

	return 0;
}

输出:


gethostbyname ---- 得到4字节整型IP地址是调用该函数的主机字节序

示例代码:

#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>

int main(int argc,char *argv[]){
	struct hostent *pret = NULL;
	if(argc < 2){
		printf("The argument is too few\n");
		return 1;
	}
	pret = gethostbyname(argv[1]);
	if(NULL == pret){
		printf("get host-%s info failed\n",argv[1]);
		return 2;
	}

	printf("The office-name is %s\n",pret->h_name);

	{
		char **ppalias = pret->h_aliases;

		while(*ppalias != NULL){
			printf("alias-name:%s\n",*ppalias);
			ppalias++;
		}

	}

	{
		struct in_addr **ppaddr = (struct in_addr **)pret->h_addr_list;

		while(*ppaddr != NULL){	
			printf("IP Address:%s\n",inet_ntoa(**ppaddr));
			ppaddr++;
		}
	}
	
	/*如果只想得到第一个4字节整型的IP地址,可以采用如下表达式:**(struct in_addr **)pret->h_addr_list
	 * */
	return 0;
}

输出:


Linux系统为发送方提供如下两个函数完成需要的字节序转换(发送方主机字节序 转换成 因特网网络字节序):

htonl: uint32_t htonl(uint32_t v)

htons: uint16_t htons(uint16_t v)

Linux系统为接收方提供如下两个函数完成需要的字节序转换(因特网网络字节序 转换成 接收方主机字节序):

ntohl: uint32_t ntohl(uint32_t v)

ntohs:uint16_t ntohs(uint16_t v)

四个函数的实现过程:
1. 判断当前主机(调用函数的程序运行用主机)的字节序是大端还是小端
2. 如果是大端,直接返回参数值
3. 如果是小端,地址值最低的字节单元 与 地址值最高的字节单元 进行交换   
             地址值次低的字节单元 与 地址值次高的字节单元 进行交换
   返回交换后组成的值  

六、因特网协议栈

一种互联网能够让不同主机上的进程进行通信,必须制定一套通信协议

网络上传输一种业务数据(与程序网络功能相关的数据,也称为应用层协议数据),不能仅传输业务数据。还需要一些其它辅助型控制数据的配合,例如:源IP地址、目的IP地址、源端口号、目的端口号等等

因特网这种互联网制定的一套协议叫TCP/IP协议栈​,采用对辅助控制数据进行分类分层的思想设计而成,分为五层:

  1. 应用层:这部分的协议内容负责业务数据的二进制位组织

    严格意义上说,这层协议内容不属于TCPIP协议栈本身,有很多种应用层协议,每一种对应一种形式网络服务

    例如常用的应用层协议:http ftp pop3 smtp 。。。。

  2. 传输层:这部分的协议内容负责进程间通信涉及的辅助控制数据的二进制位组织

    进程间通信涉及的辅助控制数据的二进制位组织方案也可以有多种,每一种称为传输层的某个协议

    常用的是以下两种:

    1> TCP ---- Transfer Control Protocol传输控制协议 ------- 使用最为频繁

    2> UDP ----- User DataGram Protocol用户数据报协议

    传输层协议还会决定应用层数据的传输方式,这也是本层名称的由来

  3. 网络层:这部分的协议内容负责主机(包括路由器)间通信涉及的辅助控制数据的二进制位组织

    主机间通信涉及的辅助控制数据的二进制位组织方案也可以有多种,每一种称为网络层的某个协议

    常用的是以下几种:

    1> IP ----- Internet Protocol ------------------使用最为频繁,也是最重要的网络层

    2> ARP

    3> RARP

    .......

  4. 数据链路层:这部分的协议内容负责统一局域网网口间通信涉及的辅助控制数据的二进制位组织

    常用的是:PPP协议

  5. 物理层:负责采用哪种传输介质传输二进制位

    严格意义上讲也不属于TCPIP协议栈的内容​

​OSI七层协议模型:在TCP/IP协议栈模型的基础上将应用层分为三个子层:应用层 表示层 会话层 ------- 一种常识,了解即可

因此对于应用程序编程而言只需学会:1. 按应用层协议组织好应用层PDU 2.发送应用层PDU 3.接收应用层PDU 4.处理应用层PDU


七、传输层传输方式

传输层除了负责进程间通信用的辅助控制数据的组织外,还会决定如何传输(发送和接收操作)应用层PDU

TCP/IP协议栈的传输层提供三种传输协议:

  1. TCP:面向连接的 可靠的 有序的 流式传输 不支持组播和广播
  2. UDP:非面向连接的 不可靠的 无序的 报式传输 可以直接组播和广播
  3. SCTP ---- 了解

面向连接:通信双方在第一次传输应用层PDU之前,需要建立好一个逻辑上的连接

可靠传输:每次发送方发送出去数据,都可以知道对方有没有接收到 ------ TCP协议代码中基于接收对方收到数据的确认信息 + 重发机制来实现的

有序传输:多个应用层PDU的发送次序,与对方接收到的次序相同

无序传输:多个应用层PDU的发送次序,与对方接收到的次序可能相同,也可能不同

流式传输:已接收数据不能再次被接收,未接收完整的数据,下次还能继续接收

报式传输:已接收数据不能再次被接收,未接收完整的剩余数据会被丢弃

组播:可以同时向处于同一组的主机发送数据

广播:可以同时向一个子网中的所有主机发送数据

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/902869.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Javaee---多线程(一)

文章目录 1.线程的概念2.休眠里面的异常处理3.实现runnable接口4.匿名内部类子类创建线程5.匿名内部类接口创建线程6.基于lambda表达式进行线程创建7.关于Thread的其他的使用方法7.1线程的名字7.2设置为前台线程7.3判断线程是否存活 8.创建线程方法总结9.start方法10.终止&…

微积分复习笔记 Calculus Volume 1 - 3.5 Derivatives of Trigonometric Functions

3.5 Derivatives of Trigonometric Functions - Calculus Volume 1 | OpenStax

西门子S7-200 SMART 多泵轮换功能库案例下载

通用描述 在现场使用多台风机水泵的场合&#xff0c;需要考虑对多台风机水泵进行轮换&#xff0c;因此如何合 理的对多台风机水泵进行轮换就成了一道难题&#xff0c;本文针对上述情况&#xff0c;专门开发了多 泵轮换的应用库&#xff0c;可以方便统计泵的运行时间&#xf…

Python print()输出颜色设置

标准格式 print("\033[显示方式&#xff1b;前景颜色&#xff1b;背景颜色m…\033[0m") 显示方式 前景颜色和背景颜色 print("\033[0;37;41m我是小杨我就这样\033[0m") print("\033[0;37;42m我是小杨我就这样\033[0m") print("\033[0;37;…

AI助理与知识库:企业新人培训的革新力量

在快速变化的商业环境中&#xff0c;企业新人培训模式的创新已成为提升组织效能的关键。特别是人工智能&#xff08;AI&#xff09;助理的引入&#xff0c;结合知识库的应用&#xff0c;为企业新人培训带来了革命性的变化。以下是对这一变革的深入探讨与前景展望&#xff0c;旨…

文本转语音工具 | Balabolka v2.15.0.880 便携版

Balabolka是一款功能强大的文本转语音&#xff08;TTS&#xff09;软件&#xff0c;它能够将文字转换成语音并保存为多种音频格式&#xff0c;如WAV、MP3、OGG或WMA。这款软件兼容多种文件格式&#xff0c;包括但不限于AZW、CHM、DjVu、DOC、EPUB、FB2、LIT、MOBI、ODT、PDF、P…

3.堆栈的理解

堆栈是同一段进行插入删除的线性表 &#xff08;先入后出&#xff09; 栈式最基础的常见的数据结构之一 进入一个新的函数的时候 会开辟一个空间&#xff0c;存放需要的数据 int add(int a,int b,int c) {return abc } int main() {add(1,2,3) }//add&#xff08;1&#xff…

Redis 线程控制 总结

前言 相关系列 《Redis & 目录》&#xff08;持续更新&#xff09;《Redis & 线程控制 & 源码》&#xff08;学习过程/多有漏误/仅作参考/不再更新&#xff09;《Redis & 线程控制 & 总结》&#xff08;学习总结/最新最准/持续更新&#xff09;《Redis &a…

https://huggingface.co/上的模型无法用linux服务器clone怎么办(只需要稍微改一下网址,就可以切换到镜像下载)

问题描述&#xff1a; 在ubuntu系统上&#xff0c;使用如下命令&#xff0c;克隆仓库&#xff0c;报无法访问错误&#xff1a; git clone https://huggingface.co/distilbert/distilroberta-base通用解决方案&#xff1a; 把下面部分更换&#xff1a; https://huggingface.…

Scrapy框架原理与使用流程

一.Scrapy框架特点 框架&#xff08;Framework&#xff09;是一种软件设计方法&#xff0c;它提供了一套预先定义的组件和约定&#xff0c;帮助开发者快速构建应用程序。框架通常包括一组库、工具和约定&#xff0c;它们共同工作以简化开发过程。scrapy框架是python写的 为了爬…

为什么有0.35/Tr这一信号带宽定义

从频域幅值函数可以近似认为这是一个低通滤波器模型&#xff0c;可以采用RC网络模型来处理&#xff0c;根据电路理论计算电压10%到90%所需上升时间&#xff0c;再根据滤波器频域特性计算幅值在-3db处的频率极限&#xff0c;通过两个关系式可以计算出频率极大值和上升时间关系&a…

<<机器学习实战>>15-26节笔记:逻辑回归参数估计、梯度下降及优化、模型评价指标

梯度下降缺点&#xff1a;有可能有鞍点&#xff08;如果不是凸函数的时候&#xff09;&#xff0c;不一定能找到最小值解决方法&#xff1a;随机梯度下降&#xff08;选一条数据&#xff09;和小批量梯度下降&#xff08;选几条数据这两个解决方法又会带来新问题&#xff0c;比…

51单片机完全学习——LCD1602液晶显示屏

一、数据手册解读 通过看数据手册我们需要知道&#xff0c;这个屏幕每个引脚的定义以及如何进行发送和接收。通过下面这张图我们就可以知道&#xff0c;这些引脚和我们的编程是有关的&#xff0c;需要注意的是&#xff0c;这里我们在接线的时候&#xff0c;一定要把DB0-DB7接到…

变流升压一体机:能源领域的新兴力量与优秀品牌

在当今能源转型的大背景下&#xff0c;变流升压一体机作为一种创新型的电力设备&#xff0c;正逐渐成为新能源领域的关键角色。 变流升压一体机是一种综合性很强的光伏箱式变电站设备&#xff0c;它将储能变流器、升压变压器、高压环网柜、低压配电箱等多种设备集成在一个集装箱…

LeetCode.冗余连接(并查集以及广度优先搜索)

684.冗余连接| 传送门&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 树可以看成是一个连通且 无环 的 无向 图。 给定往一棵 n 个节点 (节点值 1&#xff5e;n) 的树中添加一条边后的图。添加的边的两个顶点包含在 1 到 n 中间&#xff0c;且这条附加的边不属于树中…

上线 24 小时,爆了!

产研团队&#xff08;兼客服&#xff09;已爆单&#x1f525;&#x1f680;&#x1f4a5;&#xff01;&#xff08;bushi&#xff09; 在此由衷感谢各位小伙伴的信任&#x1f929;&#xff01; 还没有试用的小伙伴赶紧去围观&#x1f447;️&#x1f447;️&#x1f447;️ …

高效数据集成案例:从聚水潭·奇门到MySQL

聚水潭奇门数据集成到MySQL的技术案例分享 在企业信息化建设中&#xff0c;数据集成是实现业务流程自动化和数据统一管理的关键环节。本文将分享一个具体的系统对接集成案例&#xff1a;如何将聚水潭奇门平台上的销售出库单数据高效、可靠地集成到MySQL数据库中&#xff0c;以…

AUTOSAR-Com模块

COM 文章目录 COMCOM 基础介绍COM主要功能AUTOSAR COM 模块 发送模型Signal 信号/信号组发送信号属性—Triggered属性Pending属性信号的初始化信号的对齐方式&#xff08;大小端&#xff09;信号的收发发送接收 字节序转换和符号扩展信号的过滤机制过滤处理信号传输模式信号流和…

【十进制转十六进制数】

【十进制转十六进制数】 C语言版本C 版本Java版本Python版本 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; 从键盘接收一个整数&#xff0c;编程实现将其转换成十六进制数。 输入 一个整数 输出 十六进制数 样例输入 100样例输出 6…

day01-ElasticStack+Kibana

ElasticStack-数据库 #官网https://www.elastic.co/cn/ #下载7.17版环境准备 主机名IP系统版本VMware版本elk110.0.0.91Ubuntu 22.04.417.5.1elk210.0.0.92Ubuntu 22.04.417.5.1elk310.0.0.93Ubuntu 22.04.417.5.1 单机部署ES 1.下载ES软件包&#xff0c;放到/usr/local下 […