前言
今天整理了网络编程的下篇,主要归纳了wireshark抓数据包及分析、TCP安全可靠原因分析(三次握手、四次挥手)、数据库sqlite3及操作(shell脚本和C语言对数据库的增、删、改、查及关闭),各个知识点的代码编写及分析。
万石谷、粒粒积累 上菜!
提示:以下是本篇文章正文内容,下面案例可供参考
一、网络数据包
1 抓取网络数据包 wireshark(此软件可以用来分析网络数据报)
注意: 安装过程中会提示 安装一个组件 winpcap (需要安装)
重点: wireshark问题 过滤 tcp udp arp
1.1 分析以太网包头
第2章 链 路 层.PDF
1.2 分析IP报文
第3章IP:网际协议.PDF
UDP报文
第11章UDP:用户数据报协议.PDF
TCP报文
第17章 TCP:传输控制协议.PDF
以太网头 : 源MAC地址 目的MAC地址
IP头: 源IP地址 目的IP地址
UDP头: 源端口号 目的端口号
TCP头: 源端口号 目的端口号
1.1 以太网包头
分析以太网包头:wrieshark 抓数据包 过滤筛选:arp
以太网头 : 源MAC地址 目的MAC地址
1.2 IP报文
IP头: 源IP地址 目的IP地址
1.3 UDP报文
UDP头: 源端口号 目的端口号
1.4 TCP报文
TCP头: 源端口号 目的端口号
二、TCP(安全可靠分析)
为什么TCP安全可靠??
三次握手:连接的时候 connect --- accept
SYN -- 连接的时候
ACK -- 确认
四次挥手:断开的时候 close
FIN -- 断开的时候
ACK -- 确认
重传确认
2.1 连接(三次握手)
(1)TCP在连接的时候,需要三次握手(请详细解释一下三次握手过程)
三次握手 连接的时候用的是SYN位,确认的时候用的是ACK位
(1) 客户端给服务器发送一个请求,假设发送的序号是200,SYN=1,代表请求连接
(2) 服务器端应答,并发送一个请求 假设发送的序号是500,
确认序号是201(对客户端的发送序号200确认) ACK=1(确认) SYN=1
(3) 客户端端应答 发送的需要在原来的基础上顺序增加1,201(上一次客户端的发送序号是200),
确认序号是501(对服务器发送的序号500确认) ACK=1(确认)
2.2 断开(四次挥手)及ACK攻击
(2)TCP在断开连接的时候,需要四次挥手(请详细解释一四次挥手过程)
断开连接的时候 close()函数,用的FIN位 和 ACK位
(1)发起端: 发出断开请求 FIN=1,假设发送序号是400
(2)应答端: 发出应答 ACK=1, 假设发送序号是1000,确认序号是401(因为发起端的发出请求断开的发送序号400)
(3)应答端: 发出断开请求 FIN=1 发送序号是1001(因为应答端第一次发送的序号是1000,再一次发送在原来的基础上+1)
(4)发起端: 发出应答 ACK=1, 发送序号是401(因为发起端第一次发送序号是400),确认序号是1002(应答端发送的断开请求序号是1001)
(3)重传确认
ACK攻击:
客户端在连接服务器的时候,最后一次握手,需要给服务器一个ACK,确认我要去连接服务器
但是,客户端就不给这个ACK,让服务器处于等待,造成ACK攻击
2 客户端如何判断服务器断开
方法1: 通过recv的返回值 <= 0,如果 <=0 说明服务器出问题了
但recv 返回值 <= 0的判断可能会漏掉某些情况
方法2: 因为recv <= 0 并不能检测到所有断开情况,可以使用心跳包实现
原理: 客户端 定期(每隔 0.1秒)给服务器发送1包数据,服务收到后回应,
如果客户端检测到,发送了多包数据,服务器仍然没有回应,说明,服务器出问题了,
客户端重连,直到服务器恢复为止
流程:服务器功能: 等待客户端连接;一旦有客户端发送connect, 回应ok
客户端功能: 连接成功后,每隔 0.1秒钟发送connect, 接收服务器的ok.
如果长时间收不到ok, 客户端重新连接服务器
/////////////////////////////////////////client.c///////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
int count = 3; //客户端接收不到服务器应答的次数,如果 == 0, 说明服务器不在线
int server_on = 0; //是否连接成功标志 0,断开 1 连接
int i = 0;
int main(int argc, char *argv[])
{
int fd;
struct sockaddr_in youaddr;
youaddr.sin_family = AF_INET;
youaddr.sin_port = htons(atoi(argv[2]));
youaddr.sin_addr.s_addr = inet_addr(argv[1]);
char buf[100] = "connect";
while(1)
{
sleep(1);
if(!server_on)
{
fd = socket(AF_INET, SOCK_STREAM, 0);
int ret = connect(fd, (struct sockaddr *)&youaddr, sizeof(youaddr));
if(ret == 0)
server_on = 1; //连接成功
else
{
printf("connect error %d\n", i);
close(fd); //连接失败,因为是无限循环,1秒钟后再重连
i++;
continue;
}
}
strcpy(buf, "connect");
send(fd, buf, sizeof(buf), 0); //发送connect
memset(buf, 0, sizeof(buf));
usleep(100000);
if(server_on)
{
if(recv(fd, buf, sizeof(buf), MSG_DONTWAIT) > 0)
{
printf("buf is %s\n", buf);
if(strcmp(buf, "ok") != 0) //没收到ok
{
count--;
if(count == 0)
{
printf("server is disconnect\n");
server_on = 0;
}
}
else
count = 3;
}
else
{
count = 0;
printf("server is no answer\n");
server_on = 0;
close(fd);
}
}
}
close(fd);
}
///////////////////////////////////server.c/////////////////////////////////////////
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
int fd1;
int main()
{
int newfd, ret;
char buf[100] = { 0 };
int fd = socket(AF_INET, SOCK_STREAM, 0);
fcntl(fd, F_SETFL, fcntl( fd, F_GETFD, 0 )|O_NONBLOCK );
struct sockaddr_in myaddr;
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(55555);
myaddr.sin_addr.s_addr = htonl(INADDR_ANY); //192.168.20.252
bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr));
listen(fd, 5);
while(1)
{
newfd = accept(fd, NULL, NULL); //非阻塞等待客户端连接
if(newfd > 0)
{
printf("fd %d connect newfd %d\n", fd, newfd);
fd1 = newfd;
}
ret = recv(fd1, buf, sizeof(buf), MSG_DONTWAIT);//非阻塞等待客户端发送数据
if(ret > 0)
{
printf("recv %s\n", buf);
if(strcmp(buf, "connect") == 0) //收到了connect
{
str