抓包工具wireshark
聊天程序原理
wireshark工作原理
常用调试测试工具
使用telnet测试TCP服务器端
使用lsof
使用tcpdump
使用netstat
使用sniffer
使用wireshark
Chariot
…
SmartBit—硬件
TCP/IP协议网络封包格式
以太网头
IP头
UDP头
TCP头
TCP 的可靠传输:通过确认和重发机制
2.1.TCP 把所有要发送的数据进行编号(每一个字节用一个号)
2.2.发送时从当前数据位置,发送 window 大小的数据
面向连接:TCP握手过程
TCP三次握手,四次挥手
三次、四次握手注意点:
1.一定标注客户端和服务器
2.三次握手的连接必须是由客户端发起 (四次握手客户端和服务器都可以发起)
3. SYN,,ACK, FIN 等标志符号应该写上|
网络信息检索、网络属性设置、超时检查
网络信息检索函数
gethostname() 获得主机名
getpeername() 获得与套接口相连的远程协议地址
getsockname() 获得本地套接口协议地址
gethostbyname() 根据主机名取得主机信息 endhostent()
gethostbyaddr() 根据主机地址取得主机信息
getprotobyname() 根据协议名取得主机协议信息
getprotobynumber() 根据协议号取得主机协议信息
getservbyname() 根据服务名取得相关服务信息
getservbyport() 根据端口号取得相关服务信息
域名解析步骤:
1、添加#include <netdb.h>头文件
2、定义结构体变量hs, struct hostent* hs = NULL;
3、通过gethostbyname域名解析,将域名转换为IP地址
4、将取到服务器的32位整数IP地址
//将转化后的ip值赋值给服务器结构体变量
sin.sin_addr.s_addr = *(uint32_t*)hs->h_addr;
endhostent();//释放掉结构体变量
hs = NULL;
说明:
IPv4 中使用 gethostbyname() 函数完成主机名到地址解析,这个函数仅仅支持 IPv4,且不允许调用者指定所需地址类型的任何信息,返回的结构只包含了用于存储 IPv4 地址的空间。IPv6 中引入了 getaddrinfo()的新 API,它是协议无关的,既可用于 IPv4 也可用于 IPv6。
网络属性设置
getsockopt和setsockopt
int getsockopt(int sockfd,int level,int optname,void *optval,socklen_t *optlen)
int setsockopt(int sockfd,int level,int optname,const void *optval,socklen_t *optlen)
level指定控制套接字的层次.可以取三种值:
1)SOL_SOCKET:通用套接字选项.(应用层)
2)IPPROTO_IP:IP选项.(传输层)
3)IPPROTO_TCP:TCP选项. (网络层)
optname指定控制的方式(选项的名称),我们下面详细解释
optval获得或者是设置套接字选项.根据选项名称的数据类型进行转换
/* 允许广播 */
int b_br = 1;
setsockopt (fd, SOL_SOCKET, SO_BROADCAST, &b_br, sizeof (int));
/* 设置接收超时 */
struct timeval tout;
tout.tv_sec = 5;
tout.tv_usec = 0;
setsockopt (fd, SOL_SOCKET, SO_RCVTIMEO, &tout, sizeof (struct timeval));
网络超时
在网络通信中,很多操作会使得进程阻塞
TCP套接字中的recv/accept/connect
UDP套接字中的recvfrom
超时检测的必要性
避免进程在没有数据时无限制地阻塞
当设定的时间到时,进程从原操作返回继续运行
网络超时检测(一)
设置socket的属性 SO_RCVTIMEO
参考代码如下
struct timeval tv;
tv.tv_sec = 5; // 设置5秒时间
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv,
sizeof(tv)); // 设置接收超时
recv() / recvfrom() // 从socket读取数据
网络超时检测(二)
用select检测socket是否’ready’
参考代码如下
while(1)
{
struct fd_set rdfs;
struct timeval tv = {5 , 0}; // 设置5秒时间
FD_ZERO(&rdfs);
FD_SET(sockfd, &rdfs);
if (select(sockfd+1, &rdfs, NULL, NULL, &tv) > 0) // socket就绪
{
recv() / recvfrom() // 从socket读取数据
}
}
网络超时检测(三)
设置定时器(timer),
捕捉SIGALRM信号 参考代码如下
void handler(int signo) { return; }
struct sigaction act;
sigaction(SIGALRM, NULL, &act);
act.sa_handler = handler;
act.sa_flags &= ~SA_RESTART;//清除掉 SIGALRM 信号的 SA_RESTART
sigaction(SIGALRM, &act, NULL);
alarm(5);
if (recv(,,,) < 0) ……
思考:
试总结如何在linux中动态检查到是否有网络以及网络中途的掉线/连接的检查?
提示:
1.应用层
心跳检测
2.内核中
网卡驱动中 2.6内核里面,使能1s的周期性检查定时器
网卡硬件或者我们通过GPIO,插拔网线时候产生中断,处理相应中断 //立即检测到
心跳监测
方法1: 数据交互双方隔一段时间,一方发送一点数据到对方,对方给出特定的应答。如超过设定次数大小的时间内还是没有应答,这时候认为异常
方法 2:改变套接字的属性来实现
void setKeepAlive (int sockfd, int attr_on, socklen_t idle_time, socklen_t interval, socklen_t cnt)
{
setsockopt (sockfd, SOL_SOCKET, SO_KEEPALIVE, (const char *) &attr_on, sizeof (attr_on));
setsockopt (sockfd, SOL_TCP, TCP_KEEPIDLE, (const char *) &idle_time, sizeof (idle_time));
setsockopt (sockfd, SOL_TCP, TCP_KEEPINTVL, (const char *) &interval, sizeof (interval));
setsockopt (sockfd, SOL_TCP, TCP_KEEPCNT, (const char *) &cnt, sizeof (cnt));
}
int keepAlive = 1; //设定KeepAlive
int keepIdle = 5; //开始首次KeepAlive探测前的TCP空闭时间
int keepInterval = 5; //两次KeepAlive探测间的时间间隔
int keepCount = 3; //判定断开前的KeepAlive探测次数
setKeepAlive (newfd, keepAlive, keepIdle, keepInterval, keepCount);