1.网络基础
1.1 广域网
- 最大的广域网就是互联网;
- 互联网在世界范围内使用,有统一的标准,是无数软硬件集合达成的结果
1.2 万维网
- 所有通过 www. 进行访问的 web 服务器都是万维网服务范畴,后台 web 服务,前台浏览器交互
1.3 局域网
- 通过特定技术手段完成小范围的互联,私密性较强,较为安全
1.4 城域网
- 相对于局域网,覆盖面更广,而且比局域网使用的软硬件更加多样化,互联方式更丰富
1.5 OSI网络七层模型
- 1.应用层
- 2.表示层
- 3.会话层
- 4.传输层
- 5.网络层
- 6.链路层
- 7.物理层
1.6 TCP/IP四层网络模型
- 1.应用层:用户自定义协议的封装和发送接收
- 2.传输层:PC将数据交付给交换机或路由,进行中转;其中最重要的是 TCP 协议与 UDP 协议;端口号(port),大部分应用使用的都是80端口,例如万维网服务
- 3.网络层:通过固有技术对数据进行转发,形成网络包;最重要的是 IP 协议
- 4.物理层:定义传输介质的传输标准,对计算机的数据进行数模转换和模数转换;链路层指定了物理设备的访问方式,控制传输协议、传输错误的校验
1.7 TCP与UDP
- 1.TCP是有链接的传输层协议,需要确保双方在线,数据传输完整
- 2.UDP是无链接的传输层协议,可能会丢失数据、产生数据延时
- 3.UDP传输速度远远高于TCP
- 4.一般使用TCP进行连接,UDP进行数据传送
1.8 TCP/IP协议栈
- 1.对网络数据进行封装和剥离,最终变为以太网帧或还原为原始数据
- 2.分为三层
- 1.TCP层:添加TCP首部
- 2.IP层:添加IP首部
- 3.以太网层:添加mac首部、mac尾部
- 3.发出去的东西叫做以太网帧,大小一般为46~1500字节
1.9 mac物理地址
1.10 TCP的连接过程(三次握手四次挥手)
- 标志位:SYN(建立连接的请求)、ACK(确认请求)、FIN(断开连接请求)、RST(重置与复位)
- 本次建立连接过程规定客户端为主动方:
- 1.第一次客户端发送请求连接信息:SYN=1,序号=1000(例子,序号是一个不确定的值)
- 2.第二次服务器发送确认链接回复:SYN=1,ACK=1001,序号=8000(例子,序号是一个不确定的值)
- 3.第三次客户端发送确认连接请求:ACK=8001,序号=1001(为服务器请求的ACK)
- 本次断开连接过程规定客户端为主动方:
- 1.第一次客户端发送断开请求:FIN=1,
- 2.第二次服务器发送确认断开回复:
- 3.第三次服务器发送断开连接请求:
- 4.客户端确认连接断开回复:
1.11 TCP建立连接的状态转换
2.socket套接字
2.1 socket具有很强的跨平台能力,在所有的平台与编程环境中都可以使用socket进行网络开发
2.2 socket套接字实现网络功能,使用网络设备的一系列函数族或函数库
2.3 socket带网络中被标识的网络进程(网络进程是指使用socket套接字完成网络功能的进程)
2.4 Linux中的socket被定义为一个文件描述符(符合Linux中“万物皆文件”的说法),可以跟普通文件一样进行操作,使用读写方式直接访问网络设备
- Linux中的socket实际上就是标识了IP和端口号的网络进程
2.5 socket套接字相关函数
- accept() : 等待建立链接,服务器使用
- connect() : 请求建立连接,客户端使用
- bind() : 绑定固定端口号,被访问者使用
- listen() : 监听连接,适用于有链接的协议
- socket() : 创建socket并制定传输协议类型
- read(int socketfd, char* buf, int sizeof(buf)) : 读网络设备
- write(int socketfd, char* buf, int sizeof(buf)) : 写网络设备
2.6 网络结构
- 老版本网络结构: struct sockaddr
- 新版本网络结构: struct sockaddr_in
- 其中的 sin_port 成员指定端口
- 其中的 sin_family 成员指定ipv4还是ipv6的地址族类型
- 其中的 sin_addr.s_addr 成员是一个32位数,代表IP地址
2.7 主机序与大端序
- 1.主机序(小端序):低地址存低字节,高地址存高字节
- 2.大端序:低地址存高字节,高地址存低字节
- 3.临时数据、中转数据不需要格式转换,只有需要长期保存在网络上的数据需要转换,例如IP和端口号
2.8 大小端转换的相关函数
- ntohs() : 大端转小端 端口号
- ntohl() : 大端转小端 IP地址
- htons() : 小端转大端 端口号
- htonl() : 小端转大端 IP地址
- inet_pton()
2.9 模拟一个服务器的连接
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
int main()
{
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8000);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
bind(socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
listen(socket_fd, 128);
int client_fd;
socklen_t size = sizeof(client_fd);
if((client_fd=accept(socket_fd, (struct sockaddr*)&client_addr, &size)) > 0)
printf("Server Recive A Connect...\n");
return 0;
}
- 1.将上述代码编译为一个 server 可执行程序,运行该程序,发现阻塞;在新的终端中首先查看本机的IP地址,使用 ifconfig 命令,再使用 nc IP地址 8000 来连接 server 程序中的socket,即可模拟客户端向服务器发送连接请求的过程。
2.10 模拟一个客户端
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
int main()
{
struct sockaddr_in client_addr;
bzero(&client_addr, sizeof(client_addr));
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons(8001);
client_addr.sin_addr.s_addr = htonl(INADDR_ANY);
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
bind(socket_fd, (struct sockaddr*)&client_addr, sizeof(client_addr));
int server_fd;
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8000);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if((server_fd=connect(socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr))) == 0)
printf("Client Connect A Server...\n");
return 0;
}
- 通过上述代码编译一个 client 可执行文件,先执行 server 程序,再执行 client 程序,就可完成一个客户端向服务器发送连接请求的模拟。