网站里面嵌入的地图是怎么做的,做自媒体挣钱的网站有哪些,龙岩市住房和城乡建设局网站,电子商务是干什么的 女生学难吗网络结构模式
C/S结构 - 客户机/服务器#xff1b;采用两层结构#xff0c;服务器负责数据的管理#xff0c;客户机负责完成与用户的交互#xff1b;C/S结构中#xff0c;服务器 - 后台服务#xff0c;客户机 - 前台功能#xff1b;
优点
1. 充分发挥客户端PC处理能力…网络结构模式
C/S结构 - 客户机/服务器采用两层结构服务器负责数据的管理客户机负责完成与用户的交互C/S结构中服务器 - 后台服务客户机 - 前台功能
优点
1. 充分发挥客户端PC处理能力先在客户端处理再提交服务器响应速度快
2. 操作界面好看满足个性化需求
3. 安全性较高面向固定用户群程序更注重流程
缺点
1. 需要安装专用的客户端软件
2. 对客户端的操作系统有限制不能跨平台 B/S结构 - 浏览器/服务器将系统功能实现的核心部分集中于服务器简化系统开发维护
优点
总体成体低维护方便分布性强开发简单
缺点
1. 通信开销大系统和数据的安全性较低
2. 无法实现个性化的功能要求
3. 协议固定
4. 响应速度明显降低 MAC地址、IP地址、端口
MAC地址
网卡是一块被设计用来允许计算机在计算机网络上进行通讯的计算机硬件又称为网络透配器或网络接口卡NIC其拥有 MAC 地址属于 OS 模型的第 2层。
每个网卡都有一个被称为MAC地址的第一无二的48位串行号(以太网卡/无线网卡)
网卡的功能
1. 数据封装与解封装
2. 链路管理
3. 数据编译与译码
MAC地址 - 媒体存取控制地址/局域网地址/以太网地址/物理地址/硬件地址
MAC地址是用来确认网络设备位置的地址由网络设备制造商生产时烧录在网卡中一台设备可以有多个网卡
IP地址
IP地址是互联网的协议地址是IP协议提供的一种统一的地址格式为互联网上的每一个网络和每一台主机分配一个逻辑地址以此屏蔽物理地址的差异
A类IP地址 - 一个字节网络地址三个字节主机地址1.0.0.1 - 126.255.255.254子网掩码255.0.0.0用于广域网
B类IP地址 - 两个字节网络地址两个字节主机地址128.0.0.1 - 191.255.255.254子网掩码255.255.0.0用于城际网络
C类IP地址 - 三个字节网络地址一个字节主机地址192.0.0.1 - 223.255.255.254子网掩码255.255.255.0用于局域网 0.0.0.0 - 当前主机
255.255.255.255 - 当前子网的广播地址
IP地址不能以127开头127.0.0.1可以代表本机IP地址
子网掩码
子网掩码必须结合IP地址一起使用用于屏蔽IP地址一部分区分网络地址和主机地址
192.168.100.10/24 - IP地址192.168.100.10 子网掩码24个1
端口
设备与外界通讯交流的出口 - 虚拟端口/物理端口
虚拟端口是逻辑意义上的端口特指TCP/IP协议中的端口一个IP地址可以由65536个端口端口通过端口号标识 0 - 65535一个计算机中不能出现同样端口号的进程不用进程号的原因是因为进程号是变化的0~1023是周知端口紧密绑定一些特定服务不能自己设置使用
1024~49151为注册端口用户选择安装的一些应用程序
49152~65535 动态分配 网络模型
七层参考模型/osi参考模型
1. 物理层 - 定义物理设备的标准接口类型、传输速率
2. 数据链路层 - 提供介质访问、链路管理
3. 网络层 - IP选址、路由选择
4. 传输层 - 建立、管理、维护端到端的连接
5. 会话层 - 建立、管理、维护会话
6. 表示层 - 数据格式转化、数据加密
7. 应用层 - 为应用程序提供服务用户和网络服务的接口 TCP/IP四层模型 协议
通信双方必须共同遵从的一组约定三要素语法、语义、时序最终体现为在网络上传输的数据包格式各个层之间的协议不互相影响
应用层协议 - FTP(文件传输)/HTTP(超文本传输协议)/NFS(网络文件协议)
传输层协议 - TCP传输控制协议/UDP用户数据包协议
网络层协议 - IP因特网互联协议/ICMP因特网控制报文协议/IGMP因特网组管理协议
网络接口层协议 - ARP地址解析协议/RARP反向地址解析协议
UDP协议 TCP协议 IP协议 以太网帧协议 ARP协议 网络通信的过程
封装 - 上层协议通过封装使用下层协议提供的服务每层协议在上层数据的基础上加上自己的头部/尾部信息实现该层的功能 分用 - 帧到达主机沿着协议栈自底向上依次传递各层协议处理本层负责的头部数据获取信息 ARP协议 - 通过IP地址查找MAC地址 - 28个字节
RARP协议 - 通过MAC地址查找IP地址 Socket介绍
套接字 - 对网络中不同主机上的应用进程之间进行双向通信的端点的抽象一个套接字就是网络上进程通信的一段提供了应用层进程利用网络协议交换数据的机制上联应用程序下联网路协议栈是应用程序与网络协议进行交互的接口
通信时其中一个网络应用程序将要传输的一段信息写入它所在主机的 socket 中该 socket通过与网络接口卡 (NIC)相连的传输介质将这段信息送到另外一台主机的 socket 中使对方能够接收到这段言息。socket 是由 IP 地址和端口结合的提供向应用层进程传送数据包的机制。
在linux环境下用于表示进程间网络通信的特殊文件类型本质为内核借助缓冲区形成的伪文件
套接字通信分两部分
服务器端被动接收连接一般不主动
客户端主动向服务器发起连接
socket地址
socket地址是一个结构体 - 封装IP和端口号 sa_family是地址族类型的变量地址族类型通常与协议族相对应sa_data存放socket地址值 PF_UNIX - 文件路径名 - 108字节
PF_INET - 6个字节 16位端口号32位IP
PFINET6 - 26个字节 16位端口号32位流标识 128位IP32bit范围ID 为了方便使用提出专用的SOCKET地址 所有专用socket地址实际使用时都需要转换为通用的socket地址
socket函数
#inc]ude sys/types .h
#incIude sys/socket .h
#incTude arpa/inet .h // 包含了该头文件上面两个可以省略
int socket(int domain, int type, int protoco1);功能创建一个套接字参数domain - 协议族 AF_INET - ipv4 AF_INET6 - ipv6AF_UNIX AF_LOCAL - 本地套接字通信进程间type - 通信过程中实现的协议类型SOCK_STREAM - 流式协议SOCK_DGRAM - 报式协议protocol - 具体的协议0 - SOCK_STREAM TCP- SOCK_DGRAM UDP返回值成功 - 返回文件描述符操作的就是内核缓冲区失败 - -1
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);功能绑定fd和本地的IP/端口参数sockfd - socket函数得到的fdaddr - 需要绑定的socket地址addrlen - 第二个参数结构体的内存大小
int listen(int sockfd, int backlog);// /proc/sys/net/core/somaxconn功能监听socket上的连接参数sockfd - 文件描述符backlog - 未连接和已连接的和的最大值
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);功能接收客户端连接默认阻塞等待客户端连接进来参数sockfd - 文件描述符addr - 传出参数记录了连接成功后客户端的地址信息addrlen - 第二个参数的内存大小返回值成功 - 用于通信的文件描述符失败 - -1
int connect(int sockfd, const struct sockaddr *addr , socklen_t addrlen) ;功能客户端连接服务器参数sockfd - 用于通信的文件描述符addr - 客户端要连接的服务器的地址信息addtrlen - 第二个参数的内存大小返回值成功 - 0失败 - -1
ssize_t write(int fd, const void *buf, size_t count);
ssize_t read(int fd, void *buf,size_t count); 字节序
字节序顾名思义宁节的顺序就是大于一个宁节类型的数据在内存中的存放顺序(一个字节的数据当然就无需谈顺序的问题了)
字节序分为大端字节序和小端字节序
大端小端的判断
/*字节序判断 - 大端/小端
*/
#include iostream
using namespace std;int main(){union{short value;char byte;}test;test.value 0x0102;if(test.byte 1){cout大端存储endl;}else if(test.byte 2){cout小端存储endl;}else{cout未知endl;}return 0;
}
字节序转换函数
格式化的数据在两台不同字节序的主机之间传递会发生问题所以需要发送端先转大端接收端再根据自身情况进行转换socket提供了封装好的转换函数 s - 转换端口l - 转换IP 网络通信时需要将主机字节序转换成网络字节序大端另外一段获取到数据以后根据情况将网络字节序转换成主机字节 IP地址转换
将字符串IP转为整数/主机网络字节序转换
#include arpa/inet.h
// p - 点分十进制字符串 n - 网络字节序的整数
int inet_pton(int af, const char *src, void *dst);af - 地址族AF - INET IPV4AF - INET6 IPV6src - 需要转换的点分十进制的IP字符串dst - 转换后的结果保存在这儿
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);size - 第三个参数的大小数组大小返回值 - 转换后的数据地址和dst一样
#include iostream
#include arpa/inet.h
#includecstdio
using namespace std;// int inet_pton(int af, const char *src, void *dst);// const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);int main(){//字符串转整数char buf[] 192.168.1.4;unsigned int num 0;inet_pton(AF_INET , buf , num);unsigned char* p (unsigned char*)num;cout(int)*p (int)*(p1) (int)*(p2) (int)*(p3)endl;// 整数转字符串char ip[16] ;const char* str inet_ntop(AF_INET , num , ip , sizeof(ip));coutstrendl;return 0;
}
TCP通信流程
UDPTCP用户数据包协议传输控制协议面向无连接面向连接可以单播多播广播只能1v1单播面向数据报基于字节流不可靠的协议可靠的协议
TCP 通信流程
服务器 - 创建有一个用于监听的套接字 - 将监听的文件描述符和本地的IP、端口绑定IP 端口就是服务器的地址信息 - 设置监听监听的fd开始工作 - 阻塞等待当有客户端发起连接解除阻塞接受客户端连接得到和客户端通信的套接字 - 通信接受数据/发送数据 - 通信结束断开连接
客户端 - 创建一个用于通信的套接字 - 连接服务器需要指定连接服务器的IP/端口 - 连接成功了发生通信 - 通信结束断开连接
TCP通信实现服务端/客户端
// 实现TCP服务器端
#include iostream
#include arpa/inet.h
#includecstdio
#include unistd.h
#include string.h
using namespace std;int main(){// 1. 创建socket用于监听int lfd socket(AF_INET , SOCK_STREAM , 0);// 2. 绑定struct sockaddr_in saddr;saddr.sin_family PF_INET;inet_pton(AF_INET , 192.168.93.129 , saddr.sin_addr.s_addr);saddr.sin_port htons(9998);bind(lfd , (struct sockaddr*)saddr , sizeof(saddr));// 3. 监听listen(lfd , 8);// 4. 接收客户端连接struct sockaddr_in caddr;socklen_t len sizeof(caddr); int cfd accept(lfd , (struct sockaddr*)caddr , len);// 输出客户端的信息char client_ip[16];inet_ntop(AF_INET , caddr.sin_addr.s_addr , client_ip , sizeof(client_ip));unsigned short client_port ntohs(caddr.sin_port);coutIP:client_ip PORT: client_portendl;// 获取客户端的数据char buf[1024] {0};len read(cfd , buf , sizeof(buf));cout服务器读取数据bufendl;// 给客户端发数据const char *str hello 647;write(cfd , str , strlen(str));close(lfd);close(cfd);return 0;
}
// TCP通信客户端
#include iostream
#include arpa/inet.h
#includecstdio
#include unistd.h
#include string.h
using namespace std;int main(){// 1. 创建套接字int fd socket(AF_INET , SOCK_STREAM , 0);// 2. 连接服务器端struct sockaddr_in caddr;caddr.sin_family AF_INET;inet_pton(AF_INET , 192.168.93.129 , caddr.sin_addr.s_addr);caddr.sin_port htons(9998);connect(fd , (struct sockaddr*)caddr , sizeof(caddr));// 3. 读写数据const char *str hello zry;write(fd , str , strlen(str));char buf[1024] {0};int len read(fd , buf , sizeof(buf));cout客户端读取数据bufendl;close(fd);return 0;
}
TCP三次握手
三次握手发生在客户端丽连接调用connect底层会通过TCP协议进行三次握手
注意第三次握手可以携带数据 滑动窗口
滑动窗口的大小意味着接收方还有多大的缓冲区可用于接收数据
滑动窗口的大小会随着发送数据/接收数据而变化
通信双方都有发送缓冲区和接收缓冲区
mss: 一条数据最大的数据量
win: 滑动窗口
TCP四次挥手
发生在断开连接的时候程序调用close()会使用TCP协议进行四次挥手
客户端/服务端都可以主动发起/断开连接谁调用close()就是谁发起的
注意发起方FIN请求可以携带数据
多进程实现并发服务器
实现TCP通信服务器处理并发的任务使用多线程或者多进程解决
1. 一个父进程多个子进程
2. 父进程负责等待并接收客户端的连接
3. 子进程完成通信接收一个客户端请求就创建一个子进程
#include iostream
#include arpa/inet.h
#includecstdio
#include stdlib.h
#include unistd.h
#include string.h
#include signal.h
#include wait.h
#include errno.h
using namespace std;void fun(int arg){while(1){int ret waitpid(-1 , NULL , WNOHANG);if(ret - 1){break;}else if(ret 0){break;}else{cout回收到了子进程: retendl;}}
}int main(){// 注册信号捕捉struct sigaction act;act.sa_flags 0;sigemptyset(act.sa_mask);act.sa_handler fun;sigaction(SIGCHLD , act , NULL);// 创建int lfd socket(AF_INET , SOCK_STREAM , 0);if(lfd -1){perror(socket);exit(0);}// 绑定struct sockaddr_in saddr;saddr.sin_family AF_INET;saddr.sin_port htons(9999);saddr.sin_addr.s_addr INADDR_ANY;int ret bind(lfd , (struct sockaddr*)saddr , sizeof(saddr));if(ret -1){perror(bind);exit(0);}// 监听ret listen(lfd , 5);if(ret -1){perror(listen);exit(0);}// 不断循环等待客户端连接while(1){struct sockaddr_in caddr;socklen_t len sizeof(caddr);int cfd accept(lfd , (struct sockaddr*)caddr , len);if(cfd -1){if(errno EINTR){continue;}perror(accept);exit(0);}// 每一个连接进来创建子进程与客户端通信pid_t pid fork();if(pid 0){// 获取客户端信息char ip[16];inet_ntop(AF_INET , caddr.sin_addr.s_addr , ip , sizeof(ip));unsigned short port ntohs(caddr.sin_port);coutIP: ip port: portendl;// 接收客户端发来的数据char buf[1024] {0};while(1){int len read(cfd , buf , sizeof(buf));if(len -1){perror(read);exit(0);}else if(len 0){cout读到了数据bufendl;}else{cout已经断开连接了.....;}write(cfd , buf , strlen(buf));}}close(cfd);}close(lfd);return 0;
}
// TCP通信的客户端
#include iostream
#include stdio.h
#include arpa/inet.h
#include unistd.h
#include string.h
#include stdlib.h
using namespace std;
int main() {// 1.创建套接字int fd socket(AF_INET, SOCK_STREAM, 0);if(fd -1) {perror(socket);exit(-1);}// 2.连接服务器端struct sockaddr_in caddr;caddr.sin_family AF_INET;inet_pton(AF_INET , 192.168.93.129 , caddr.sin_addr.s_addr);caddr.sin_port htons(9999);int ret connect(fd, (struct sockaddr *)caddr, sizeof(caddr));if(ret -1) {perror(connect);exit(-1);}// 3. 通信char recvBuf[1024];int i 0;while(1) {sprintf(recvBuf, data : %d\n, i);// 给服务器端发送数据write(fd, recvBuf, strlen(recvBuf)1);int len read(fd, recvBuf, sizeof(recvBuf));if(len -1) {perror(read);exit(-1);} else if(len 0) {printf(recv server : %s\n, recvBuf);} else if(len 0) {// 表示服务器端断开连接printf(server closed...);break;}sleep(1);}// 关闭连接close(fd);return 0;
}
多线程实现并发服务器 - client同多进程并发
#include iostream
#include arpa/inet.h
#include cstdio
#include stdlib.h
#include unistd.h
#include string.h
#include pthread.h
using namespace std;struct sockInfo{int fd;pthread_t tid;struct sockaddr_in addr;
};struct sockInfo sockinfos[128];void *work(void * arg){// 子线程和客户端通信 cfd/客户端信息/线程号// 获取客户端信息struct sockInfo *pinfo (struct sockInfo *)arg;char ip[16];inet_ntop(AF_INET , pinfo-addr.sin_addr.s_addr , ip , sizeof(ip));unsigned short port ntohs(pinfo-addr.sin_port);coutIP: ip port: portendl;// 接收客户端发来的数据char buf[1024] {0};while(1){int len read(pinfo-fd , buf , sizeof(buf));if(len -1){perror(read);exit(0);}else if(len 0){cout读到了数据bufendl;}else{cout已经断开连接了.....;break;}write(pinfo-fd , buf , strlen(buf)1);}close(pinfo-fd);return NULL;
}int main(){// 创建int lfd socket(AF_INET , SOCK_STREAM , 0);if(lfd -1){perror(socket);exit(0);}cout1;// 绑定struct sockaddr_in saddr;saddr.sin_family AF_INET;saddr.sin_port htons(9999);saddr.sin_addr.s_addr INADDR_ANY;int ret bind(lfd , (struct sockaddr*)saddr , sizeof(saddr));if(ret -1){perror(bind);exit(0);}// 监听ret listen(lfd , 5);if(ret -1){perror(listen);exit(0);}// 初始化数据int max sizeof(sockinfos)/sizeof(sockinfos[0]);for(int i 0 ; imax ; i){bzero(sockinfos[i] , sizeof(sockinfos[i]));sockinfos[i].fd -1;sockinfos[i].tid -1;}// 不断循环等待客户端连接子线程创建while(1){struct sockaddr_in caddr;socklen_t len sizeof(caddr);int cfd accept(lfd , (struct sockaddr*)caddr , len);struct sockInfo *pinfo;for(int i 0 ; imax ; i){// 从数组中找到可用的sockInfoif(sockinfos[i].fd -1){pinfo sockinfos[i];break;}if(i max - 1){sleep(1);i--;}}pinfo-fd cfd;memcpy(pinfo-addr , caddr , len);// 每一个连接进来创建子线程与客户端通信pthread_t tid;pthread_create(pinfo-tid , NULL , work , pinfo);pthread_detach(pinfo-tid);}close(lfd);return 0;
}