首页 > 系统相关 >网络编程 Linux环境 C语言实现

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

时间:2024-10-28 18:45:26浏览次数:9  
标签:编程 字节 主机 IP地址 C语言 Linux 因特网 应用层 端口号

进程间通信的延续

跨电脑进程间通信


一、远程通信方式

  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的发送次序,与对方接收到的次序可能相同,也可能不同

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

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

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

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

标签:编程,字节,主机,IP地址,C语言,Linux,因特网,应用层,端口号
From: https://blog.csdn.net/2301_77329667/article/details/143310112

相关文章

  • 青少年编程与数学 02-002 Sql Server 数据库应用 16课题、安全机制
    青少年编程与数学02-002SqlServer数据库应用16课题、安全机制课题摘要:一、安全机制1.身份验证(Authentication)2.授权(Authorization)3.角色(Roles)4.加密(Encryption)5.审计(Auditing)6.其他安全特性二、身份验证1.Windows身份验证模式(WindowsAuthenticationMod......
  • linux shell特殊参数
    $n功能描述:n为数字,$0代表命令本身,$1-$9代表第一到第九个参数,十以上的参数需要使用大括号包含,如${10}$*功能描述:这个变量代表命令行中的所有参数,此命令把所有参数看成一个整体$@功能描述:这个变量也代表命令行中的所有的参数,但是此命令把每个参数区分对待注意:$*与$@区别在于......
  • 实验二 类和对象_基础编程1
    1.实验任务1验证性实验:简单类T的定义和测试。实践、阅读代码,回答问题。这个简单任务覆盖以下内容:类的定义(封装)类的使用:对象的创建、访问数据共享机制在同一个对象的所有操作之间共享数据——实现机制:封装在同一个类的所有对象之间共享数据......
  • 实验2 类和对象_基础编程1
    实验任务1t.h源代码//类T:声明classT{//对象属性、方法public:T(intx=0,inty=0);//普通构造函数T(constT&t);//复制构造函数T(T&&t);//移动构造函数~T();//析构函数voidadjust(intratio);//......
  • 水仙花数c语言程序:实操解答
    水仙花数(Narcissisticnumber)是指一个三位数,其各个位上数字的立方和等于该数本身。比如153就是水仙花数,因为\(1^3+5^3+3^3=153\)。以下是一个C语言程序,用于判断一个三位数是否为水仙花数,并输出100到999范围内的所有水仙花数:```c#include<stdio.h>#include<math.h>......
  • 黑客入门Linux安装准备工作
    ArsenalLinux黑客新手入门推荐:社区采用二个系统进行更新后续文章,分别如下:-Kalilinux:内包含大量工具/一次下载安装可以减少所需要工具安装时间。退求其次:Kali是目前最火爆的黑客工具集成系统。最关键的是网上教程很多,方便更多爱好者实战自己的才能。Linuxmint:目前......
  • 黑客新手入门应该懂的Linux 细节知识
    Linux到底是什么?Linux是_*一个_*家族开源的类Unix操作系统基于Linux内核l.Linux是LinusTorvalds的创意。显然.他制作Linux是为了好玩,并于1991年9月17日发布了Linux的第一个版本。据传Linux的创造者打算将他的发明命名为Freax,但未经LinusTorvalds......
  • Linux系统中的信号
    目录一、信号的概念二、信号处理1.信号处理的三种方式(1)默认处理(2)忽略处理 (3)自定义处理(信号捕捉)2.信号处理的时机 3.自定义捕捉的另一个函数sigaction4.sigaction函数中的sa_mask三、信号产生的方式1.使用kill命令,向指定进程发送信号2.使用键盘3.系统调用......
  • C语言和Rust在安全性特性上的区别
    #C语言和Rust在安全性特性上的区别在探讨C语言和Rust在安全性特性上的区别时,我们可以明确地指出几个核心观点:Rust提供了内存安全保证、并发安全、以及错误处理机制,这些特性在编译时就能够避免许多常见的错误类型,显著提高了软件的安全性和可靠性。其中,内存安全保证是Rust最为突......
  • 在linux系统中,手动编写java代码,将接口打成jar供其他程序调用,实现方式
    本文是在学习java时做的记录工作目录:/root/JAVA1、编写接口文件IHello.java,将IHello.java文件放到usr/com/example目录下注意:usr不是根目录下的/usr,是在当前目录下创建usr/com/example,因为package需要指定目录。目录结构:.└──usr└──com└──......