网络
网络编程就是用来实现网络互连的不同计算机上运行的程序间可以进行数据交换的手段。
-
网络相关的硬件设备:
- 网卡 路由器 交换机 数据传输(媒介) 光纤(光缆) 数字信号 模拟信号 解调器 中继器 集线器 网线
-
网络相关的协议(事先约定好流程、规则)
- HTTP 超文本传输协议 HTTPS
- FTP 文件传输协议
- TCP:传输控制协议
- UDP:用户数据报协议
- IP:因特网互联协议
- ARP/RARP 地址解析协议 逆地址解析协议
-
IP地址: ipv4 192.168.88.xxx 由4个255以内的整数组成
-
一个网络中的IP地址,唯一的,唯一标识网络中的一台设备
-
IP地址好比手机电话号码
-
-
子网掩码: IP地址&子网掩码 == 网络地址
- IP址&(~子网掩码) == 本地IP地址
基本概念
ISO/OSI
七层模型
- 理论
- 国际标准化组织(International Organization for Standardization,简称为ISO)是标准化领域中的一个国际性非政府组织。
- 开放式系统互联通信参考模型(英语:Open System Interconnection Reference Model,缩写为 OSI),简称为OSI模型(OSI model),一种概念模型,由国际标准化组织提出,一个试图使各种计算机在世界范围内互连为网络的标准框架。
- 对网络进行划分,分为七层
+-------------------+---------------------+
| 应用层 | Application |
+-------------------+---------------------+
| 表示层 | Presentation |
+-------------------+---------------------+
| 会话层 | Session |
+-------------------+---------------------+
| 传输层 | Transport |
+-------------------+---------------------+
| 网络层 | Network |
+-------------------+---------------------+
| 数据链路层 | Data Link |
+-------------------+---------------------+
| 物理层 | Physical |
+-------------------+---------------------+
- 物理层: (并不是指传送数据的物理设备,不是光纤,不是网线)
- 主要是定义物理设备标准,如网络的接口类型、光纤的接口类型、各种传输介质的传输速率等。
- 主要作用是传输比特流(0/1 电流的强弱表示 数模转换和模数转换)
- 物理层的数据: 比特
- 物理设置: 中继器 集线器
- 数据链路层:
- 定义了如何让格式化数据以帧为单位进行传输,以及如何控制对物理介质的访问
- 串口实验 115200
- 通常提供错误检测和纠正 奇偶检验 CRC
- 数据链路层数据: 帧
- 物理设置:网桥、交换机
- 网络层:
- 在位于不同地址位置的网络中的两个主机系统之间提供连接和路径选择。
- 网络层物理设备: 路由器
- 传输层:
- 主要是将从下层接收到数据进行分段和传输,到达目的地址后再进行重组
- 数据传输层: 数据段
- 会话层:
- 负责建立、管理、和终止表示层实体之间的会话
- 表示层:
- 提供作用于应用层数据的编码和转换,数据压缩和解压、加解密、数据转换等
- 应用层:
- 为计算机用户提供应用接口,为用户提供各种网络服务
- HTTP、HTTPS、FTP、POP3、SMTP
- 设备:网关
TCP/IP 网络模型
-
实践
-
对网络划分为四层
ISO/OSI七层网络模型 TCP/IP四层网络模型
+-------------------+---------------------+-----------------+-------------+
| 应用层 | Application | | HTTP |
+-------------------+---------------------+ | FTP |
| 表示层 | Presentation | 应用层 | SMTP |
+-------------------+---------------------+ | HTTPS |
| 会话层 | Session | | TELNET |
+-------------------+---------------------+-----------------+-------------+
| 传输层 | Transport | 传输层 | TCP UDP |
+-------------------+---------------------+-----------------+-------------+
| 网络层 | Network | 网络层 | IP ICMP IGMP ARP ARAP |
+-------------------+---------------------+-----------------+-------------+
| 数据链路层 | Data Link | | |
+-------------------+---------------------+ 网络接口(链路)层 |PPP PPPOE |
| 物理层 | Physical | | |
+-------------------+---------------------+-----------------+-------------+
IP地址
-
IP地址(Internet Protocol Address)是指互联网协议地址,又译为网际协议地址
-
IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。
-
IPv4 4字节 32二进制位 理论上 2^32(43亿) 个IP地址
- 4字节 32个二进制位
- 表示方式
- 点分十进制 由4个0-255的整数用.隔开 192.168.88.233
- 整数十六进制 0xC0A858E9 高位左右 低位在右
- IPv4地址分级
- A级: 0+7位网络地址 + 24位本地址址 0000 0000 – 0111 1111 128 1.x.x.x
- B级: 10+14位网络地址 + 16位本地地址
- C级: 110 + 21位网络地址 + 8位本地地址
- D级: 1110 + 28位多播地址
- E级: 11110 + 开关 将来实验所有
类别 最大网络数
网络地址个数IP地址范围 单个网段最大主机数 私有IP地址范围 A 126(2^7-2) 1.0.0.1-127.255.255.254 16777214 10.0.0.0-10.255.255.255 B 16384(2^14) 128.0.0.1-191.255.255.254 65534 172.16.0.0-172.31.255.255 C 2097152(2^21) 192.0.0.1-223.255.255.254 254 192.168.0.0-192.168.255.255 -
IPv6 号称能为地球上每一粒沙子分配一个IP地址 16字节 128二进制位
- 表示方法
- 冒号十六时制 X:X:X:X:X:X:X:X 每一个X都是4位的十六进制(16bit 两个字节)
- ABCD:EF01:2345:6789:ABCD:EF01:2345:6789 X的前导0是可以省略的
- 0位压缩表示法
- 在某些情况下,一个IPv6地址中间可能包含很长的一段0,可以把连续的一段0压缩为“::”。但为保证地址解析的唯一性,地址中”::”只能出现一次
- FF01:0:0:0:0:0:0:1101 → FF01::1101
- 0:0:0:0:0:0:0:1 → ::1
- 0:0:0:0:0:0:0:0 → ::
- 内嵌IPv4地址表示法
- 了实现IPv4-IPv6互通,IPv4地址会嵌入IPv6地址中,
- 此时地址常表示为:X:X:X:X:X:X:d.d.d.d,前96b采用冒分十六进制表示,而最后32b地址则使用IPv4的点分十进制表示,例如::192.168.0.1与::FFFF:192.168.0.1就是两个典型的例子,注意在前96b中,压缩0位的方法依旧适用
- 冒号十六时制 X:X:X:X:X:X:X:X 每一个X都是4位的十六进制(16bit 两个字节)
- 表示方法
-
子网掩码
- IP地址 & 子网掩码 ==== 网络地址
- IP: 192.168.88.233
- 子网掩码:255.255.255.0
- 网络地址:192.168.88.0
- 本地地址:233
- 按正常来讲A类网络的子网掩码: 255.0.0.0 B级网络的子网掩码:255.255.0.0 C级网络:255.255.255.0
-
超网
- 对子网络的重新划分 192.168.88.233:24 前面24个二进制位是子网掩码
- 192.168.88.233:10 网络地址:192.128.0.0 10子网掩码(1111 1111 1100 0000 )
- x.y.z.k:n n子网掩码 表示子网掩码前n个二进制位为1,后面32-n个二进制为0
特殊的网址
- 每一个字节都为0的地址(“0.0.0.0”)对应于当前主机;
- IP地址中的每一个字节都为1的IP地址(“255.255.255.255”)是当前子网的广播地址;
- IP地址中凡是以“11110”开头的E类IP地址都保留用于将来和实验使用。
- IP地址中不能以十进制“127”作为开头,该类地址中数字127.0.0.1到127.255.255.255用于回路测试,如:127.0.0.1可以代表本机IP地址,用“http://127.0.0.1”就可以测试本机中配置的Web服务器。
- 网络ID的第一个6位组也不能全置为“0”,全“0”表示本地网络。
端口号
本质上是一个unsigned short类型的数据
逻辑上表示一个参与通信的进程
端口好在
IP地址转换
IP地址定义
//基本地址类型 所有的函数接口都是以此类型为定义的
struct sockaddr{
sa_family_t sa_family; //地址簇 值都是用宏赋值 int
char sa_data[14]; //通信地址
};
//本地地址类型 本地通信
#include <sys/un.h>
struct sockaddr_un{
sa_family_t sun_family;
char sun_path[]; //套接字文件(socket文件)路径
};
//网络通信地址类型 ipv4
struct sockaddr_in{
sa_family_t sin_family; //地址簇
in_port_t sin_port; //端口号
struct in_addr sin_addr; //ipv4地址
};
struct in_addr{
in_addr_t s_addr; //32位无符号整数
};
typedef uint32_t in_addr_t;
//ipv6
struct sockaddr_in6{
sa_family_t sin6_family;
__be16 sin6_port;
__be32 sin6_flowinfo;
struct in6_addr sin6_addr;
__u32 sin6_scope_id;
};
struct in6_addr{
//in_addr_t s_addr;
union{
_u8 u6_addr8[16];
__be16 u6_addr16[8];
__be32 u6_addr32[4];
}in6_u;
#define s6_addr in6_u.u6_addr8
#define s6_addr16 in6_u.u6_add16
#define s6_addr32 in6_u.u6_add32
};
IP地址转换
- 书写ip地址和编程中需要传递地址
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//只能处理IPv4的地址
//用"192.168.88.233" 点分十进制的IPv4地址格式转换为 0xC0A858E9(大端) 0XE958A8C0(小端)
int inet_aton(const char *cp, struct in_addr *inp);
in_addr_t inet_addr(const char *cp);
in_addr_t inet_network(const char *cp);
//根据32位无符号整数的IPv4地址转换为点分十进制的IP地址
char *inet_ntoa(struct in_addr in);
#include <arpa/inet.h>
//本地转换网络ip地址
int inet_pton(int af, const char *src, void *dst);
/*
af 取值:
AF_INET ipv4 src 点分十进制 dst: struct in_addr类型的内存地址
AF_INET6 ipv6 src 冒号十六时制 dst: struct in6_addr类型的内存地址
*/
//网络ip地址转本地ip地址
const char *inet_ntop(int af, const void *src,char *dst, socklen_t size);
/*
af 取值:
AF_INET ipv4 src struct in_addr类型 dst:点分十进制 size:INET_ADDRSTRLEN
AF_INET6 ipv6 src struct in6_addr类型 size:INET6_ADDRSTRLEN
*/
端口号
- 本质上是一个unsigned short类型的数据 0-65535
- 逻辑上表示一个参与通信的进程
- 端口号在编程里需要给定网络字节序
- 0-1024端口一般被系统和知名协议占用
- FTP-21 TELNET-23 WWW-80
字节序
- 大端 网络字节序 网络中一律采用大端
- 小端 PC终端基本采用小端
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong); //home to network l uint32_t s uint16_t
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
socket套接字
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
//创建socket套接字
/*
domain: 地址族/域
AF_UNIX/AF_LOCAL/AF_FILE : 本地通信
AF_INET : 基于ipv4的网络通信
AF_INET6 : 基于ipv6的网络通信
AF_PACKET : 基于底层包接口的网络通信
type: 通信协议
SOCK_STREAM : 数据流协议 TCP协议
SOCK_DGRAM : 数据报协议 UDP协议
protocol : 特别通信协议 一般置0即可
*/
成功返回套接字描述符,失败返回-1
- 套接字描述符类似于文件描述符,UNIX把网络当作文件看待
- 向网络中发送数据即写文件,从网络中接收数据即读取文件
绑定通信地址
- socket套接字,如果想要进行通信,则需要绑定到唯一的物理地址
- 本地通信,网络通信通信地址是不一样的,但是绑定的方法是一样的
- bind参数struct sockaddr* 但实际上传递的是struct sockaddr_un*或者struct sockaddr_in * 或者struct sockaddr_in6 *
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
/*
功能: 把socket套接字sockfd绑定到物理通信地址my_addr上面
参数:
sockfd: socket函数的返回值
my_addr: 具体通信的地址内存 取值是struct sockaddr_un* /struct sockaddr_in * /struct sockaddr_in6 *
addrlen: 第二个参数指向通信地址的内存长度
返回值: 成功返回0 失败返回-1 并且设置errno
*/
-
socket套接字在通信之前,如果没有调用bind函数,那么会自动绑定到一个ip地址和port上面
-
在编程过程中,服务器创建socket为了能够让客户端连接上来,所以需要显示地绑定到明确的ip和port上面
-
在编程过程中,客户端创建socket往往不会调用bind函数来绑定,因为客户端随机绑定即可
请求连接
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
/*
功能:让socket套接字连接到指定的通信地址 请求连接 连接本地通信地址 连接网络的通信地址
*/
本地通信样例
环境为Ubuntu20
服务器端代码:
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
//socket本地通信 基于 socket文件进行数据传递
#define SOCK_FILE "my.sock"
int main(int argc,char *argv[]){
printf("1.服务器 创建socket套接字...\n");
int sockfd = socket(AF_LOCAL,SOCK_DGRAM,0);
if(sockfd == -1){
perror("socket");
return -1;
}
printf("2.socket套接字关联到socket文件...\n");
struct sockaddr_un addr; //本地通信地址类型
addr.sun_family = AF_LOCAL; //地址族
strcpy(addr.sun_path,SOCK_FILE);//socket文件
//绑定到物理内存时 创建socket文件
int ret = bind(sockfd,(struct sockaddr*)&addr,sizeof(addr));
if(ret != 0){
perror("bind");
return -1;
}
printf("3.服务器 循环接收数据...\n");
for(;;){
char buf[1024] = {};
ssize_t rb = read(sockfd,buf,sizeof(buf));
if(rb == -1){
perror("read");
return -1;
}
if(rb == 0){
break;
}
if(strcmp(buf,"!quit")==0){
break;
}
printf("recv: %s\n",buf);
}
printf("4.服务器 读取数据完毕,关闭服务器!\n");
close(sockfd);
printf("5.删除套接字文件!\n");
unlink(SOCK_FILE);
return 0;
}
用户端代码:
/*************************************************************************
* File Name: 05localclient.c
* Author: unite
* Tel: 18758077967
* Created Time: 2022年09月05日 星期一 15时34分49秒
************************************************************************/
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#define SOCK_FILE "my.sock"
int main(int argc,char *argv[]){
printf("1.客户端 创建套接字...\n");
int sockfd = socket(AF_LOCAL,SOCK_DGRAM,0);
if(sockfd == -1){
perror("socket");
return -1;
}
printf("2.客户端 准备连接到服务器socket通信地址...\n");
struct sockaddr_un addr;
addr.sun_family = AF_LOCAL;
strcpy(addr.sun_path,SOCK_FILE);
int ret = connect(sockfd,(const struct sockaddr*)&addr,sizeof(addr));
if(ret != 0){
perror("connect");
return -1;
}
printf("3.客户端 循环发送数据...\n");
for(;;){
printf(">");
char buf[1024] = {};
fgets(buf,1024,stdin);
int len = strlen(buf);
if(buf[len-1] == '\n'){
--len;
buf[len] = '\0';
}
if((ret = write(sockfd,buf,len+1))<0){
perror("write");
return -1;
}
if(ret == 0 || strcmp(buf,"!quit")==0){
break;
}
}
printf("4.客户端:关闭套接字!\n");
close(sockfd);
return 0;
}
最终的结果:
(http://t.csdn.cn/BgVaS)
通信模式
-
一对一的通信 (Peer to Peer)
-
一对多的通信 服务器/客户端(Server/Client C/S)
- C/S client/server 英雄联盟
- 优点
- 稳定性好
- 效率高
- 客户端提前缓存数据,减少运行期间对服务器数据的传输要求
- 缺点
- 需要开发服务器和客户端
- 从用户角度需要安装额外的客户端
- 更新 客户端也需要升级
- 服务器和客户端通用性不好
- 优点
- B/S browser/server 4399
- 优点
- 统一的访问服务器的方式 只需要安装浏览器
- 通用性和兼容性比较好
- 维护成本也比较低 更新
- 缺点
- 稳定性差
- 网络延时比较大
- 实时性不太好
- 数据不能提前缓存 (现在的浏览器都具备一定的缓存能力)
- 优点
- C/S client/server 英雄联盟
-
异构的网络模型 底层都是socket
socket本地通信
- 依赖于socket文件
- socket本地通信优点是稳定性好
网络通信
- 一对一的网络通信
# sudo apt-get install net-tools
# ping 192.168.88.120 #测试当前主机和192.168.88.120是否有网络
\