目录
0x01 网络编程的基础复习
1.协议:大家都遵守的规则
2.网络架构:
五层网络架构:
- 应用层:应用程序
- 传输层:四层交换机 光猫
- 网络层: 三层交换机 路由器
- 数据链路层:网桥(淘汰)二层交换机
- 物理层: 中继器 集线器
七层网络架构:将应用层拆分成了三层,应用层=应用层+表示层+会话层,为了便于开发者编程时去区分。
- 应用层
- 功能:文件传输 email ftp文件服务器,虚拟终端
- 协议:ftp tftp http (smtp pop3) telnet
- 表示层
- 功能:数据格式化,代码转换,数据加密
- 协议:
- 会话层
- 功能:建立或解除与其他连接的关系
- 协议:
- 传输层
- 功能:建立端对端的接口
- 协议:TCP UDP
- 网络层
- 功能:为数据选择路由
- 协议:IP
- 数据链路层
- 功能:传输有地址的数据 错误检测
- 协议:SLIP CSLIP ppp ppp3
- 物理层
- 功能:用来传输电信号,光信号
- 协议: ISO2110 IEEE802(无线电协议)
3.ip地址:本质是一个大小为32位的无符号整数,我们平常用点分十进制的字符串表示
4.端口:就是套接字的编号,一共有65536个端口 0到65535 即用16bit存储该编号
一般我们开发程序使用1W以上的端口比较安全
0x02 TCP协议的使用
cs 架构:client server架构,app、木马 本质上都是cs架构
bs 架构:browser server 架构 ,web应用 是bs架构,必须要借助于浏览器,并且离不开http协议
windows上的CS架构的编程套路:
服务器 Server | 客户端 Client |
1.获取协议版本:WSAStartup | 1.获取协议版本 |
2.创建套接字:socket | 2.创建套接字 |
3.创建协议地址族:SOCKADDR_IN | 3.获取服务器的协议地址族 |
4.绑定:bind | |
5.监听:listen | |
6.接受客户端连接:accept (三次握手建立连接) | 4.连接服务器 conn |
7.通信:fwrite、send、recv、sendto、recvfrom | 5.通信 |
8关闭套接字::closeSocket (四次挥手断开连接) | 6关闭套接字 |
9.清理协议信息:WSACleanup | 7.清理协议信息 |
注意:TCP建立的数据传输通道是全双工的。
数据传输通道:
单工:单向收发,例如电视机,收音机
半双工:双向收发,但同一时刻只能收或者发,例如对讲机
全双工:双向同时收发 ,例如 电话
0x03 TCP服务器
// Server.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
#include <windows.h>
int main()
{
//1.获取版本信息
WSADATA wsaData;
//参数1:协议版本号 WORD 类型
//参数2:存储版本信息的结构体的地址
WSAStartup(MAKEWORD(2, 2), &wsaData);
//MAKEWORD是一个宏函数,传入两个字节类型的数据,整合成一个WORD类型的数据
//MAKEWORD(2,2) 就是产生一个高字节为2,低字节为2的16位的数据
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
printf("得到的版本号不正确,请求版本失败\n");
return -1;
}
else {
printf("请求版本成功\n");
}
//2 创建tcp socket
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (SOCKET_ERROR == serverSocket) { //如果返回值为-1
printf("创建tcp套接字失败:%d\n",GetLastError());
return -1;
}
printf("创建socket成功\n");
//3 创建协议地址族 (配置控制信息)
SOCKADDR_IN serverAddr = { 0 };
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.107"); //将点分十进制转化32位unsigned int
serverAddr.sin_port = htons(10001); //因为我们的主机是小端系统,路由器交换机是大端系统,所以我们发给大端系统的端口号应该小端转大端
//4 绑定
int r = bind(serverSocket,(sockaddr*) &serverAddr, sizeof serverAddr);
if (-1 == r) {
printf("绑定失败!\n");
closesocket(serverSocket);
WSACleanup();
return -1;
}
printf("绑定成功!\n");
//5 监听
r = listen(serverSocket, 10);
if (-1 == r) {
printf("监听失败!\n");
closesocket(serverSocket);
WSACleanup();
return -1;
}
printf("监听成功!\n");
//6 接收客户端连接
SOCKADDR_IN clientAddr = { 0 }; //用于接收客户端的协议地址族(就是控制信息)
int len = sizeof clientAddr; //用于接收客户端协议地址族信息的大小
SOCKET connClient = accept(serverSocket, (sockaddr*)&clientAddr, &len);
//SOCKET connClient = accept(serverSocket, NULL, NULL); //如果不想存储客户端的协议地址族信息,可以传NULL地址
if (SOCKET_ERROR == connClient) {
printf("接收客户端连接失败!\n");
closesocket(serverSocket);
WSACleanup();
return -1;
}
//inet_ntoa() 将32位unisigned int 转化为点分十进制的string
printf("有客户端连接到服务器了:%s:%d!\n",inet_ntoa(clientAddr.sin_addr),clientAddr.sin_port);
//7 通信
char buff[1024];
while (1) {
r = recv(connClient, buff, 1023, NULL);//最多接收1023,最后一位留给结束符号
//最后一个参数为flag 标志接收方式,NULL表示阻塞方式
//返回值是接收到数据的长度
if (r > 0) {
buff[r] = 0; //让buff的最后一个字符为\0,因为字符串以\0为结束标志
printf("%s::%s\n", inet_ntoa(clientAddr.sin_addr), buff);
}
}
//8 关闭socket
closesocket(serverSocket);
//9 清除协议版本
WSACleanup();
while (1);
return 0;
}
0x04 TCP 客户端
// Client.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
#include <windows.h>
int main()
{
//1.获取版本信息
WSADATA wsaData;
//参数1:协议版本号 WORD 类型
//参数2:存储版本信息的结构体的地址
WSAStartup(MAKEWORD(2, 2), &wsaData);
//MAKEWORD是一个宏函数,传入两个字节类型的数据,整合成一个WORD类型的数据
//MAKEWORD(2,2) 就是产生一个高字节为2,低字节为2的16位的数据
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
printf("得到的版本号不正确,请求版本失败\n");
return -1;
}
else {
printf("请求版本成功\n");
}
//2 创建tcp socket
SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (SOCKET_ERROR == clientSocket) { //如果返回值为-1
printf("创建tcp套接字失败:%d\n", GetLastError());
return -1;
}
printf("创建socket成功\n");
//3 配置服务器协议地址族 (配置控制信息)
SOCKADDR_IN serverAddr = { 0 };
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.107"); //将点分十进制转化32位unsigned int
serverAddr.sin_port = htons(10001); //因为我们的主机是小端系统,路由器交换机是大端系统,所以我们发给大端系统的端口号应该小端转大端
//4 连接服务器
int r;
r = connect(clientSocket, (sockaddr*)&serverAddr, sizeof serverAddr);
if (SOCKET_ERROR == r) {
printf("连接服务器失败\n");
return -1;
}
printf("连接服务器成功!\n");
//5 通信
char buff[1024];
while (1) {
memset(buff, 0, 1024);
printf("请输入要发送的数据:");
scanf("%s", buff);
r = send(clientSocket, buff, strlen(buff),NULL);
if (r > 0) {
printf("发送%d字节数据成功!\n", r);
}
else {
printf("发送失败!\n");
}
}
//6 关闭socket
closesocket(clientSocket);
//7 清除协议版本
WSACleanup();
while (1);
return 0;
}