目录
D类:4个字节网络地址 + 0个字节主机地址 ---》 多播(组播)
6.跟踪ip命令tracert tracert www.baidu.com
htons: 主机数据转网络数据 host to net short
ntohs: 网络数据转主机数据 net to host short
十九、字符串转成整数函数(将手写的IP传进函数内需要转成int型才可用)atoi函数
二十、数据的接收与发送函数recv和send(也可使用以前的文件IO 的读写函数read和write)
一、IP地址:
1.概念
*IP协议提供的一种统一的地址格式,
*它为互联网上的每一个网络和每一台主机分配一个逻辑地址,
*以此来屏蔽物理地址的差异。
2.ip分类
IPV4 -- 4个字节
IPV6 -- 16个字节
3.IPV4的姿势:
192.168.101.5 ---》点分十进制
4.IPV4的组成:
网络地址 + 主机地址
主机地址:不能全部为0或者全部为1
---》全部为0 ---网络id号
---》全部为1 ---广播地址
5.IPV4分类:
A类:1个字节网络地址 + 3个字节主机地址
网络地址:以0开头
取值范围:
00000000.0.0.1 ~ 01111111.255.255.254
0.0.0.1 ~ 127.255.255.254
B类:2个字节网络地址 + 2个字节主机地址
网络地址:以10开头
取值范围:
10000000.0.0.1 ~ 10111111.255.255.254
128.0.0.1 ~ 191.255.255.254
C类:3个字节网络地址 + 1个字节主机地址
网络地址:以110开头
取值范围:
11000000.0.0.1 ~ 11011111.255.255.254
192.0.0.1 ~ 223.255.255.254
---->我们的IP : 192.168.101.5
D类:4个字节网络地址 + 0个字节主机地址 ---》 多播(组播)
网络地址:以1110开头
取值范围:
11100000.0.0.0 ~ 11101111.255.255.255
224.0.0.0 ~ 239.255.255.255
E类:网络地址: 11110开头 ,待留后用
6.跟踪ip命令tracert tracert www.baidu.com
该命令会把电脑经过哪些ip直至百度网址的其他路由器的ip地址打印出来效果如下
二、子网掩码
1.概念
用于减少IP浪费,细化IP分类,判断若干个网络是否在同一局域网内的机制
2.表现形式:
网络地址+主机地址
网络地址全部为1 主机地址全部为0
3.姿势
255.255.255.0 ====》 3个字节的网络地址 1个字节主机地址
[192.168.101.5/24] ----》 /24 代表 前 24位 子网掩码的 网络地址
4. 判断是否在同一网络下的规则:
ip地址 & 子网掩码 -----》 网络id号
如果网络id号相同,则在同一网络下
192.168.101.5 & 255.255.255.0 ----》 192.168.101.0
192.168.101.10 & 255.255.255.0 ----》 192.168.101.0
----》就说 192.168.101.5 和 192.168.101.10 在同一网络下
5.将主机地址 分出 一部分 作为 子网地址
255.255.255.1110000
192.168.101.0011000 & 255.255.255.1110000 ----》 192.168.101.0010000
192.168.101.0111000 & 255.255.255.1110000 ----》 192.168.101.0110000
称: 192.168.101.24 与 192.168.101.56 不在同一网络
6.网关:
网关(Gateway)又称网间连接器、协议转换器。默认网关在网络层以上实现网络互连,是最复杂的网络互连设备,仅用于两个高层协议不同的网络互连。网关的结构也和路由器类似,不同的是互连层。网关既可以用于广域网互连,也可以用于局域网互连。其实质是一个网络通向另外一个网络的IP地址
三、网络、互联网、因特网
*》网络由若干个节点和连接这些节点的链路组成
*》多个网络还可以通过路由器互连起来,就构成了\一个覆盖范围更大的网络,即互联网(网络的网络)
*》因特网(Internet)是世界做大的互联网。
四、Internet历史
第一阶段
*》1969年,第一个分组交换机ARPANET诞生
*》70年代中期,研究多种网络之间的互连
*》1983年,TCP/IP协议成为ARPANET的标准协议\(因特网诞生)
第二阶段:
*》1985年,NSF围绕六个大型计算机中心创建NFSNET
*》1990年,ARPANET正式关闭
*》1991年,因特网由政府转移个私人公司,开始收费
第三阶段:
*》1993年,NSFNET被商用因特网主干网替代,\由因特网服务提供者ISP来运营
*》1994年,万维网(www)促使因特网迅猛发展
*》1995年,NSFNET停止运行,因特网商业化
五、ISP
* Internet Service Provider(因特网服务提供者)
* 中国电信,中国联网,中国移动
* 为已经缴费的使用者提供可以联网通信的IP地址
六、网络分类
*》按交换技术分类:
*电路交换网络
*报文交换网络
*分组交换网络
*》按使用者分类:
*公用网
*专用网
*》按传输介质分类:
*有线网络
*无线网络
*》按覆盖范围分类:
*广域网(WAN)
*城域网(MAN)
*局域网(LAN)
*个域网(PAN)
*》按拓扑结构分类:
*总线型网络
*星型网络
*环形网络
*网状型网络
七、数据如何生成帧 从 客户机 通过网络 发送出去:
微信中: 数据 ----》 将其打包 ---》 帧 --》 网络 --》 对方
八、计算机网络体系结构
为了使不同体系结构的计算机网络都能互联,国际标准\化组织于1977年成立了专门了研究机构研究该问题不久\就提出了一个标准框架OSI架构(开放系统互连参考模型)
/* OSI */
*》OSI架构(七层):
--------------
| 应用层 |
--------------
| 表示层 |
--------------
| 会话层 |
--------------
| 传输层 |
--------------
| 网络层 |
--------------
| 数据链路层 |
--------------
| 物理层 |
--------------
(法律上的国际标准)
/* TCP/IP */
*》TCP/IP架构(四层)
--------------
| 应用层 |
--------------
| 传输层 |
--------------
| 网际层 |
--------------
| 网络接口层 |
--------------
(事实上的国际标准)
*>OSI失败原因:
*OSI专家缺乏实际经验
*协议过分复杂,运行效率低
*OSI层次划分不合理,有些功能重复出现
*>TCP/IP:
*将数据链路层和物理层合并为网络接口层
*将会话层和表示层合并到了应用层
*将网络层更名为网际层(因为使用的是IP协议)
/* 原理体系 */
*》原理体系架构(五层)
--------------
| 应用层 | 通过应用进程的交互实现网络应用
--------------
| 传输层 | 解决进程间基于网络通信的问题 (TCP UDP 端口对端口)
--------------
| 网络层 | 解决在多个网络上传输的问题 (IP地址 寻找路线)
--------------
| 数据链路层 | 解决在一个网络上的传输问题
--------------
| 物理层 | 解决使用何种信号表示比特的问题
--------------
(适于教学的架构)
九、端口号:
2个字节 65536
用户使用时端口在5001-65536之间,建议范围内越大越好
十、数据通信原理
*》数据发送的整个流程:
*》 数据
*》应用层 :HTTP+数据 (HTTP报文)
*》传输层 :TCP+HTTP+数据 (TCP报文)
*》网络层 :IP+TCP+HTTP+数据 (IP报文)
*》数据链路层: ETH+IP+TCP+HTTP+数据+ETH (帧)
*》物理层:前导码+帧 将帧看成比特流
*》路由器转发过程
*物理层 : 去掉前导码 ---》 帧
*数据链路层: 去掉帧头帧尾 ---》 IP数据报
*网络层: 分析IP数据报确认路线重新打包IP数据报
*数据链路层: 添加帧头帧尾 ---》 帧
*物理层 : 前导码+帧 将帧看成比特流
*》数据接受的整个流程:
*物理层 : 去掉前导码 ---》 帧
*数据链路层:去掉帧头帧尾 ---》 IP数据报
*网络层: 去掉IP协议头 ---》 TCP+HTTP+数据
*传输层: 去掉端口协议头 ---》 HTTP+数据
*应用层: 去掉协议头 ---》 数据
补充
ARP请求: 通过IP地址得到物理地址
RARP请求:通过物理地址 得到 IP地址IP数据报的生存时间:
TTL : 跳 次数 8
十一、TCP数据报
URG : 紧急数据
SYN表示建立连接,
FIN表示关闭连接,
ACK表示响应,
PSH表示有 DATA数据传输,没有缓冲,直接发送给应用层
RST表示连接重置
十二、传输层
TCP UDP
TCP:事先必须建立连接,数据传输稳定,可靠,不丢包
UDP:不需要连接,不可靠,可能会丢包
十三、TCP: 三次握手 四次挥手 (异常重要)
三次握手: 1. 客户端给服务器发送SYN连接请求
2. 服务器给客户回复了确认序列ACK,并发起SYN连接请求
3. 客户端给服务器回复了确认序列ACK
四次挥手: 1. 客户端给服务器发送FIN断开请求,并回复确认序列ACK
2. 服务器给客户端回复了确认序列ACK
3. 服务器给客户端发送FIN断开请求,并回复确认序列ACK
4. 客户端给服务器回复确认序列ACK
十四、socket(套接字)编程:
*socket:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
解释:
创建socket套接字
参数:
domain : 协议
AF_UNIX, AF_LOCAL Local communication unix(7)
AF_INET IPv4 Internet protocols ip(7)
AF_INET6 IPv6 Internet protocols ipv6(7)
type:
SOCK_STREAM :流式套接字 (TCP)
SOCK_DGRAM : 数据报套接字 (UDP)
SOCK_RAW : 原始套接字
protocol : 默认0
返回值:
int :成功返回socket文件描述符
失败返回-1 并设置错误码
*bind:绑定
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
原型:int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
解释:
绑定IP和PORT(端口)
参数:
sockfd :sock套接字
addr :struct sockaddr *
struct sockaddr {
sa_family_t sa_family; //unsigned short类型
char sa_data[14];
}// 加起来 16个字节
addrlen : addr的长度
返回值:
成功返回0
失败返回-1 并设置错误码
grep "struct sockadd_in {" /usr/src/linux-hwe-5.4-headers-5.4.0-122/include/* -rn
该命令用于查找结构体struct sockadd_in {
用grep查找结构体 grep -R "struct task_struct {" /usr/src 加-n可以显示行号
IPV4:
#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */
struct sockaddr_in {
__kernel_sa_family_t sin_family; /* Address family 地址系列 */
__be16 sin_port; /* Port number 端口号 */
struct in_addr sin_addr; /* Internet address ip地址 *//* Pad to size of `struct sockaddr'. */
unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -
sizeof(unsigned short int) - sizeof(struct in_addr)] ;
};struct in_addr {
__be32 s_addr;
};IPV6:
struct sockaddr_in6本地:
struct sockaddr_un
十五、主机数据与网络数据转换
概念:
由于主机的数据大都采用小端序来进行存储,然而在网络传输中,则必须是大端序的顺序来进行传输,故我们在把主机内的数据上传到网络前,必须将数据转化为大端序的形式,才能使它在网络的传输中能正确传输,其中传输到指定位置的时候,我们还得让数据从大端序转化回小端序让另外一台主机解析,故从服务器中有从大端序转小端序的函数。
htons: 主机数据转网络数据 host to net short
ntohs: 网络数据转主机数据 net to host short
函数原型: #include <arpa/inet.h>
uint16_t htons(uint16_t hostshort);
uint16_t ntohs(uint16_t netshort);
*inet_aton
*inet_ntoa
*inet_addr
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char *cp, struct in_addr *inp);
主机地址转网络地址
cp : 点分十进制ip地址
inp : struct in_addr
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
char *inet_ntoa(struct in_addr in);
网络地址转主机地址
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
in_addr_t inet_addr(const char *cp);
主机地址转网络地址
cp : 点分十进制ip地址
in_addr_t :网络数据类型的ip
十六、监听:listen
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
*解释:
监听,将主动连接变成被动连接
参数:
sockfd : sock套接字
backlog: 允许同一瞬间同时连接服务器的客户数量
返回值:
成功返回0
失败返回-1 并设置错误码
十七、阻塞等待客户端的连接:
accept:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数:
sockfd : sock套接字
addr : struct sockaddr * 客户端的数据(IP和PORT)
addrlen: addr的长度指针 socklen_t *
返回值:
成功返回文件描述符
失败返回-1 并设置错误码
十八、connect: 连接服务器
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
参数:
sockfd : sock套接字
addr : 服务器的IP和PORT
addrlen: addr的长度
返回值:
成功返回0
失败返回-1 并设置错误码
十九、字符串转成整数函数(将手写的IP传进函数内需要转成int型才可用)atoi函数
#include <stdlib.h>
函数原型 :int atoi(const char *str );
功能:把字符串转换成整型数。
参数str:要进行转换的字符串
返回值:每个函数返回 int 值,此值由将输入字符作为数字解析而生成。 如果该输入无法转换为该类型的值,则atoi的返回值为 0。
说明:当第一个字符不能识别为数字时,函数将停止读入输入字符串。
二十、数据的接收与发送函数recv和send(也可使用以前的文件IO 的读写函数read和write)
recv:接收
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
参数:
sockfd : 文件描述符(套接字)
buf : 读取数据存储的位置
len : 长度
flags :0 阻塞
返回值:
成功返回得到的字节数
失败返回-1 并设置error
掉线则返回0
send:发送
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
参数:
sockfd : 文件描述符(套接字)
buf : 读取数据存储的位置
len : 长度
flags :0 阻塞
返回值:
成功返回发送的字节数
失败返回-1 并设置error
实验案例1
客户端1:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc,char *argv[])
{
if(argc!=3){
printf("usage:%s <ip> <port>\n",argv[0]);
exit(-1);
}
//创建socket套接字
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0){
perror("socket error");
exit(-1);
}
//连接服务器
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[2]));
server.sin_addr.s_addr = inet_addr(argv[1]);;
int ret = connect(sockfd,(struct sockaddr *)&server,sizeof(server));
if(ret){
perror("connect error");
exit(-1);
}
char buf[100];
while(1){
bzero(buf,sizeof(buf));
scanf("%s",buf);
write(sockfd,buf,strlen(buf));
}
close(sockfd);
return 0;
}
服务器端1:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define PORT 12345
#define IP "192.168.101.5"
int main(void)
{
//创建socket套接字
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0){
perror("socket error");
exit(-1);
}
//绑定IP和PORT
struct sockaddr_in server;//16个字节可以被另外一个16字节的结构体强转
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.s_addr = INADDR_ANY; //自动获取到IP
// server.sin_addr.s_addr = inet_addr(IP);//在sin_addr下有struct in_addr结构体,该结构体下有s_addr成员被_b32修饰
//inet_aton(IP,&server.sin_addr);
int ret = bind(sockfd,(struct sockaddr *)&server,sizeof(server));
if(ret){
perror("bind error");
exit(-1);
}
//监听,将主动连接变成被动连接
ret = listen(sockfd,30);
if(ret){
perror("listen error");
exit(-1);
}
//阻塞等待客户端的连接
struct sockaddr_in client;
int len = sizeof(client);
int fd = accept(sockfd,(struct sockaddr *)&client,&len);//accept 函数
if(fd<0){
perror("accept error");
exit(-1);
}
printf("%d号技师上线了\n",fd);
printf("客户IP:%s\n",inet_ntoa(client.sin_addr));
printf("客户PORT:%hu\n",ntohs(client.sin_port));
char buf[100];
int n = 10;
while(1){
bzero(buf,sizeof(buf));
ret = read(fd,buf,sizeof(buf));
if(ret>0){
printf("骚年<ip:%s>说:%s\n",inet_ntoa(client.sin_addr),buf);
n = 10;
}else if(ret==0){
printf("客户逃跑了\n");
close(fd);
break;
}else{
while(n--)
continue;
close(fd);
break;
}
}
close(fd);
close(sockfd);
return 0;
}
实验案例2
客户端2:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
void *readMsg (void *arg)
{
int fd = *(int *)arg;
char buf[100];
int n = 10;
int ret;
while(1){
bzero(buf,sizeof(buf));
ret = recv(fd,buf,sizeof(buf),0);
if(ret>0){
printf("技师说:%s\n",buf);
n = 10;
}else if(ret==0){
printf("技师逃跑了\n");
close(fd);
exit(-1);
}else{
while(n--)
continue;
close(fd);
exit(-1);
}
}
}
int main(int argc,char *argv[])
{
if(argc!=3){
printf("usage:%s <ip> <port>\n",argv[0]);
exit(-1);
}
//创建socket套接字
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0){
perror("socket error");
exit(-1);
}
//连接服务器
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[2]));
server.sin_addr.s_addr = inet_addr(argv[1]);;
int ret = connect(sockfd,(struct sockaddr *)&server,sizeof(server));
if(ret){
perror("connect error");
exit(-1);
}
pthread_t thread;
pthread_create(&thread,NULL,readMsg,&sockfd);
pthread_detach(thread);
char buf[100];
while(1){
bzero(buf,sizeof(buf));
scanf("%s",buf);
send(sockfd,buf,strlen(buf),0);
}
close(sockfd);
return 0;
}
服务器端2:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#define PORT 12345
#define IP "192.168.101.5"
struct sockaddr_in client;
void *readMsg (void *arg)
{
int fd = *(int *)arg;
char buf[100];
int n = 10;
int ret;
while(1){
bzero(buf,sizeof(buf));
ret = recv(fd,buf,sizeof(buf),0);
if(ret>0){
printf("骚年<ip:%s>说:%s\n",inet_ntoa(client.sin_addr),buf);
n = 10;
}else if(ret==0){
printf("客户逃跑了\n");
close(fd);
exit(-1);
}else{
while(n--)
continue;
close(fd);
exit(-1);
}
}
}
int main(void)
{
//创建socket套接字
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0){
perror("socket error");
exit(-1);
}
int on = 1;
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
//绑定IP和PORT
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.s_addr = INADDR_ANY; //自动获取到IP
// server.sin_addr.s_addr = inet_addr(IP);
//inet_aton(IP,&server.sin_addr);
int ret = bind(sockfd,(struct sockaddr *)&server,sizeof(server));
if(ret){
perror("bind error");
exit(-1);
}
//监听,将主动连接变成被动连接
ret = listen(sockfd,30);
if(ret){
perror("listen error");
exit(-1);
}
//阻塞等待客户端的连接
unsigned int len = sizeof(client);
int fd = accept(sockfd,(struct sockaddr *)&client,&len);
if(fd<0){
perror("accept error");
exit(-1);
}
printf("%d号技师上线了\n",fd);
printf("客户IP:%s\n",inet_ntoa(client.sin_addr));
printf("客户PORT:%hu\n",ntohs(client.sin_port));
pthread_t thread;
pthread_create(&thread,NULL,readMsg,&fd);
pthread_detach(thread);
char buf[100];
while(1){
bzero(buf,sizeof(buf));
scanf("%s",buf);
send(fd,buf,strlen(buf),0);
}
close(fd);
close(sockfd);
return 0;
}