io模型+网络常用工具+协议头分析+套接字选项设置

一、IO多路复用并发服务器模型(看相关解读文件夹)

select.c

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <string.h>

#include <sys/select.h>

 

int main(int argc, const char *argv[])

{

int listenfd, connfd;

int ret;

struct sockaddr_in seraddr, cliaddr;

char buf[1024] = "\0";

socklen_t addrlen = sizeof(cliaddr);

int maxfd;

int i;

fd_set g_rdfs, c_rdfs;

//step 1: 创建套接字接口

listenfd = socket(AF_INET, SOCK_STREAM, 0);

if(-1 == listenfd)

{

perror("socket failed");

return -1;

}

//step 2: 绑定IP + Port

memset(&seraddr, 0, sizeof(seraddr));

seraddr.sin_family = AF_INET;

seraddr.sin_port = htons(8888);

seraddr.sin_addr.s_addr = inet_addr("127.0.0.1");

ret = bind(listenfd, (struct sockaddr *)&seraddr, sizeof(seraddr));

if(-1 == ret)

{

perror("bind");

return -1;

}

//step 3:监听连接

ret = listen(listenfd, 5);

if(-1 == ret)

{

perror("listen");

return -1;

}

FD_ZERO(&g_rdfs);

FD_SET(listenfd, &g_rdfs);

maxfd = listenfd;

 

while(1)

{

c_rdfs = g_rdfs;

 

ret = select(maxfd + 1, &c_rdfs, NULL, NULL, NULL);

if(-1 == ret)

{

perror("select");

exit(-1);

}

else

{

for(i = 0; i <= maxfd; i++)

{

if(FD_ISSET(i, &c_rdfs))

{

if(listenfd == i)

{

connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &addrlen);

if(-1 == connfd)

{

perror("accept");

return -1;

}

printf("connect successfully: client IP : %s, Port : %d\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));

FD_SET(connfd, &g_rdfs);

maxfd = maxfd > connfd ? maxfd : connfd;

}

else

{

ret = recv(i, buf, sizeof(buf), 0);

if(-1 == ret)

{

close(i);

FD_CLR(i, &g_rdfs);

}

else

{

ret = send(i, buf, sizeof(buf), 0);

if(-1 == ret)

{

close(i);

return -1;

}

}

}

}

}

}

}

 

close(listenfd);

 

return 0;

}

 

 

二、网络常用工具的使用(看相关解读文件夹)

(1)lsof(list open file)列举出当前系统所打开的文件

(1)lsof会访问内核打开的各种文件,所以需要root用户身份去运行

sudo lsof

(2)lsof -p <pid> 显示指定进程打开的文件

(3)lsof filename 显示指定文件在哪些进程中被打开

(4)lsof -d fd 显示所有拥有文件描述符是fd的进程

lsof -d 5

(5)lsof -i:端口号

lsof -i TCP

lsof -i @ip地址

(6)当内存中还有进程打开你意外删除的文件的时候,可以使用lsof恢复

lsof | grep filename //查看打开这个文件的进程

cd /proc/4068/fd //切换到/proc文件系统

cat fd > filename // 将删除的文件从内存倒回磁盘

 

(2)netstat 命令用于显示各种网络相关信息,如网络连接,路由表,接口状态 (Interface Statistics)等(了解)

netstat -a 列举出所有的网络连接

netstat -at/-au 只列举tcp或udp

netstat -atln 显示绑定的ip地址

netstat -atlnp ……并显示进程号

netstat -s 打印每个协议使用的情况

netstat -ts/ netstat -us

netstat -ie 等价于ifconfig

(3)telnet 检测TCP服务是否能够正常使用(万能客户端,常用网络测试)

检测tcp 相应端口号是否可以正常使用

telnet 127.0.0.1 8888(万能的客户端)

(4)wireshark 网络抓包工具

 

 

(5)tcpdump 网络抓包工具(当你的Linux无法使用图形化界面的时候)

监视指定网络接口的数据包:

sudo tcpdump -i lo

如果不指定网卡,默认tcpdump只会监视第一个网络接口,一般是eth0,下面的例子都没有指定网络接口。

指定过滤数据报的类型

sudo tcpdump tcp -i lo

抓取完整的数据包

抓取数据包时默认抓取长度为68字节。加上-s 0 后可以抓到完整的数据包

sudo tcpdump tcp -i lo -s 0

和wireshark结合起来使用,用tcpdump抓包,用wireshark查看,

保存成cap文件,方便用ethereal(即wireshark)分析

sudo tcpdump tcp -i lo -s 0 -w ./1.cap

三、常见协议头分析

(1)TCP包头

[1]源端口号:该报文段是哪个服务发出的

[2]目的端口号:该报文段需要哪个服务接收。

[3]序号(sequence number):

一次TCP通信(从TCP连接建立到断开)过程中某一个传输方向上的字节流的每个字节的编号。

随机值ISN(Initial Sequence Number,初始序号值)。

后续的TCP报文段中序号值将被系统设置成ISN加上该报文段所携带数据的第一个字节在整个字节流中的偏移。

[4]确认号(acknowledgement number):

用作对另一方发送来的TCP报文段的响应。其值是期待下一次收到的TCP报文段的序号值。

[5]头部长度(header length):

其值表示该TCP头部有多少个32bit字(4字节)。因为4位最大能表示15,所以TCP头部最长是60字节。

[6]标志位(TCP flag):

ACK标志:表示确认号是否有效(ACK标志位置1),表示该数据包是对收到数据的一种回应。

PSH标志:

提示接收端应用程序应该立即从TCP接收缓冲区中读走数据,为接收后续数据腾出空间

SYN标志:表示请求建立一个连接。(三次握手)

 

注意:携带SYN标志位的TCP数据包,协议规定长度为1

只携带ACK标志位的TCP数据包(该数据仅仅只是回应),协议规定长度为0

 

 

 

 

 

(2)UDP包头

udp的报length是1比特代表一字节---2^16字节==64kb ,而tcp的表头length是1比特代表一字(4字节)---2^4字 ==60字节;

为什么不统一呢??

 

(3)IP包头

TTL(TIME TO LIVE)存时间字段设置了数据报可以经过的最多路由器数(数据包没经过一个路由器TTL的值就会被减1,TTL值被减到0时,

该数据包就会被丢弃)

协议(Protocol,PROT),指该封包携带的上层网络协议类型

TTL的存在是为了不让全网瘫痪

 

(4)以太网包头

所用协议:用于标识上层协议

0800 IP

0806 ARP

8035 RARP

网络数据是多个包连续的,这些包怎末划分的??

四、套接字选项设置(网络属性设置)

fcntl (文件设置)

setsockopt (套接字设置)

网络通信的实现涉及多个层次,通过设置不同层次的套机字属性可以实现不同的功能

setsockopt

level : 按照协议分层,与协议没有任何关系的归到SOL_SOCKET(通用套接字选项)

 

#include <sys/types.h> /* See NOTES */

#include <sys/socket.h>

 

(1)获取套接字选项

int getsockopt(int sockfd, int level, int optname,

void *optval, socklen_t *optlen);

  1. sockfd : 套接字描述符
  2. level : 套接字选项所属层 SOL_SOCKET IPPROTO_IP IPPRO_TCP
  3. optname: 套接字选项(具体选项参考讲义) SO_BROADCAST 
  4. optval : 保存套接字选项值的缓冲区首地址
  5. optlen : 保存选项值的长度

 

返回值

成功 0

失败 -1并设置出错码

 

(2)设置套接字选项

int setsockopt(int sockfd, int level, int optname,

const void *optval, socklen_t optlen);

  1. sockfd : 套接字描述符
  2. level : 套接字选项所属层
  3. optname: 套接字选项(具体选项参考讲义)
  4. optval : 需要设置的套接字选项值的缓冲区首地址
  5. optlen : 选项值的长度

 

返回值

成功 0

失败 -1并设置出错码

 

 

注意:

  1. level :

因为套接字的选项有很多,为了便于管理所以根据,套接字选项被定义的具体层次来分类。

  1. 参考讲义我们发现套接字选项的具体值的数据类型不一样

主要因为套接字选项可粗略的分为两大类:

一类用于开启或关闭某个特性称为(标志选项),这一类大多对应int,开启某项功能置1,关闭置0。

另一类可以设置特定的值我们称为(值选项),这类选项对应特定的结构体。

  1. 通用套接字选项SOL_SOCKET,这一类选项实现和具体协议无关(换句话说,它们是内核中的协议无关代码实现的,而不是诸如IPV4之类协议去定义的),可以适用于不同的协议和不同协议层。

五、网络超时检测

  1. 在网络通信中,很多操作会使得进程阻塞
  2. TCP套接字中的recv/accept/connect
  3. UDP套接字中的recvfrom
  4. 超时检测的必要性:

避免进程在没有数据时无限制地阻塞,

当设定的时间到时,进程从原操作返回继续运行。

1.通过设置套接字选项(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读取数据

 

如果这个sockfd是SOCK_STREAM的话,

要先绑定,再监听,然后接受请求,顺序不能乱

为什吗?

 

struct timeval {

long tv_sec; /* seconds */

long tv_usec; /* microseconds */

 

};

2.select检测是否超时 -----多路复用有等待时间设置

select参数中自带时间检测(多路复用)!

在Linux中,select会修改时间,所以每次用都要设置

3.设置定时器alarm SIGALRM(终止进程)

sigaction--------这个系统调用的作用是改变进程接收到的指定信号的行动

signal函数:作用1:站在应用程序的角度,注册一个信号处理函数 作用2:忽略信号,设置信号默认处理 信号的安装和回复

注意:一个进程只能有一个闹钟,新闹钟会取代旧的闹钟

alarm(0) 取消闹钟

闹钟加signal();??不对,看下面

信号掩码

STGCHLD的来源有很多的,看红字

这里没有用掩码!!用的sa_flags!!???sa_flags信号处理选项与那三个表无关

清标志

SA_RESTART 0000 0100

1111 1011

flag = 0100 1000

flag = flag | SA_RESTART = 0100 1100

 

flag = flag & ~SA_RESTART = 0100 1000

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值