标签 NetWork 下的文章

Python 发送HEAD包

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import urllib2
import socket

def send(url):
	request = urllib2.Request(url,)
	try:
		request.get_method = lambda: 'HEAD'
		response = urllib2.urlopen(request)
		msg = response.msg
		print "message : %s"%msg
		headers = response.headers
		print "\n\n%s"%headers
		data = response.read()
		print "data\n%s"%data
	except urllib2.HTTPError,e:
		code = e.code
		print code
	except Exception,e:
		print e

socket.setdefaulttimeout(2)
send("http://74.91.23.207/")

Head方法要求响应与GET请求一样,但是没有响应体(response body)。如果我们只对关于网页或资源的
信息感兴趣,而不想检索资源本身的全部内容,可以使用HEAD命令。HEAD的使用方法与GET相同,只是不返
回Web页的正文内容。

CRC 校验的基本过程

采用 CRC 校验时,发送方和接收方用同一个生成多项式 g(x) , g(x) 是一个 GF(2) 多项式,并且 g(x) 的首位和最后一位的系数必须为 1 。

CRC 的处理方法是:发送方用发送数据的二进制多项式 t(x) 除以 g(x) ,得到余数 y(x) 作为 CRC 校验码。校验时,以计算的校正结果是否为 0 为据,判断数据帧是否出错。设生成多项式是 r 阶的(最高位是 x^r )具体步骤如下面的描述。

发送方:

1 )在发送的 m 位数据的二进制多项式 t(x) 后添加 r 个 0 ,扩张到 m+ r 位,以容纳 r 位的校验码,追加 0 后的二进制多项式为  T(x) ;

2 )用 T(x) 除以生成多项式 g(x) ,得到 r 位的余数 y(x) ,它就是 CRC 校验码;

3 )把 y(x) 追加到 t(x) 后面,此时的数据 s(x) 就是包含了 CRC 校验码的待发送字符串;由于 s(x) = t(x) y(x) ,因此 s(x) 肯定能被 g(x) 除尽。

接收方:

1 )接收数据 n(x) ,这个 n(x) 就是包含了 CRC 校验码的 m+r 位数据;

2 )计算 n(x) 除以 g(x) ,如果余数为 0 则表示传输过程没有错误,否则表示有错误。从 n(x) 去掉尾部的 r 位数据,得到的就是原始数据。

accept()函数

今天在优化Web服务器的时候发现了一个问题,抓包的时候看了下,这是chrome处理的过程,发起的连接

一看已经有很多次三次握手了,那不是有很多个连接了。但是我的web服务器是单线程的啊?并且是阻塞

的,按理说每次都应该阻塞在accept那里,为什么会建立这么多次连接了呢?

仔细想想,协议栈里面是存在一个请求队列的,listen()函数就是把请求的socket放到队列中,而accept呢就

是从队列中取出一个socket,然后返回套接字的标识,该sock就从队列中删除了。所以上面wireshark抓出来

的包有这么多次连接是正常。

自己动手学TCP/IP–http协议(http报文格式)

HTTP(HyperText Transport Protocol,超文本传送协议)

HTTP请求报文


http请求数据包的格式:头部(request line + header)+  数据(data)

头部和数据包体通过一个空行来隔开,头部的格式主要包括请求行+请求头部。如下图

HTTP请求头

请求行


请求行由请求方法字段URL字段HTTP协议版本字段3个字段组成,它们用空格分隔如:

GET /index.html HTTP/1.1。

HTTP协议的请求方法有GET、POST、HEAD、PUT、DELETE、OPTIONS、TRACE、CONNECT。这里介绍最常用的GET方法和POST方法。

GET方式:在URL里面就说明要请求的资源,URL里面包含参数,“?”后面就是参数,而“?”前面就是URL的结束。“?ip=192.168.156.11&active=on”这种就是GET方式的包,而服务器把客户端请求的内容在数据段里面发回给客户端。

POST方式:传输的数据不在URL里面出现,而是在数据段里面出现。但是请求头部多了Content-Type和Content-Length两个字段。

请求头部


请求头部由(关键字:<空格>值)对组成,每行一对,关键字和值用英文冒号“:<空格>”分隔。请求头部通知服务器有关于客户端请求的信息,典型的请求头有:

User-Agent:产生请求的浏览器类型。

Accept:客户端可识别的内容类型列表。

Host:请求的主机名,允许多个域名同处一个IP地址,即虚拟主机。

下面是GET包的一个例子:传输的数据在URL里

再看看POST包的例子:传输的数据在数据段里面


HTTP响应报文


HTTP响应也由两个个部分组成,分别是:响应头(状态行+消息报头)+响应正文

状态行格式如下:

HTTP-Version Status-Code Reason-Phrase CRLF

HTTP-Version表示服务器HTTP协议的版本;Status-Code表示服务器发回的响应状态代码;Reason-Phrase表示状态代码的文本描述。状态代码由三位数字组成,第一个数字定义了响应的类别,且有五种可能取值。

1xx:指示信息--表示请求已接收,继续处理。

2xx:成功--表示请求已被成功接收、理解、接受。

3xx:重定向--要完成请求必须进行更进一步的操作。

4xx:客户端错误--请求有语法错误或请求无法实现。

5xx:服务器端错误--服务器未能实现合法的请求。

下面是http响应包的例子

自己动手学TCP/IP--tftp协议

TFTP(Trivial File Transfer Protocol,简单文件传输协议

1.tftp的服务端口号是69

2.tftp是基于udp协议的

3.tftp是明文传输的,是一种比较轻量型的协议,一般用于bootloader加载内核

TFTP工作流程

服务端开启tftp服务,tftp是一种stand_alone服务,不是常驻内存的,是在有需要的时候才去调用的。首先,客户端发送一个读(RRQ:2个字节)或者写(WRQ:2个字节)的请求,数据包的目标端口是69。对于读或者写的报文格式如下:

RRQ/WRQ(2个字节)+文件名(N字节)+0(1字节)+模式(N字节)+0(1字节)

目前模式字段主要有2种:netascii,这是8位的ASCII码形式;另一种是octet,这是8位源数据类型。对于netascii是把回车和换行(CR/LF)解释成两个字节的。可以查看http://www.firefoxbug.com/?p=1041

tftp-server接收到数据包:如果是发现是读(RRQ),就重新随机分配一个端口,直接发送数据(DATA:2个字节)+块编号(2个字节),然后是0~512字节数据包。客户端接收到数据包,发给服务端(ACK:2个字节)+块编号(2个字节)。如果是普通的数据包,那么数据段的大小一定是512字节,如果是最后一个数据包,肯定是小于512字节的。tftp就是通过发现了一个数据段小于512字节的数据包来声明结束文件的传输了。那么一个要传输的文件刚还是512字节的整数倍怎么办呢?tftp会在最后传输一个数据段大小是0包。

tftp-server接收到数据包:如果发现是写(WRQ),服务端就发回(ACK:2个字节)+(块编号0:2个字节)的包,接着客户端就发送(DATA:2个字节)+(块编号1:2个字节)+数据段给服务端,服务端发回(ACK:2个字节)+(块编号1:2个字节)。。。依次发送。

错误信息是系统自定义的,格式主要是error(2个字节)+错误码(2个字节)+错误信息(N个字节)

下面是tftp数据包的格式图

下面是C语言解析tftp包的一小段代码:

struct tftphdr {
short th_opcode; /* packet type */
union {
unsigned short tu_block; /* block # */
short tu_code; /* error code */
char tu_stuff[1]; /* request packet stuff */
} __attribute__ ((__packed__)) th_u;
char th_data[1]; /* data or error string */
} __attribute__ ((__packed__));

// 解析udp包,packet_buffer是用rawsocket抓出来的以太网包,
void ParseUDPPacket(unsigned char *packet_buffer)
{
struct ethhdr *eth_header;//以太网头
struct iphdr *ip_header; //ip头
struct udphdr *udp_header; //tcp头
eth_header = (struct ethhdr*)packet_buffer;
ip_header = (struct iphdr*)(packet_buffer + sizeof(struct ethhdr));
udp_header = (struct udphdr*)(packet_buffer + sizeof(struct ethhdr) + ip_header->ihl*4);
unsigned char *data = NULL;
data = (packet_buffer + sizeof(struct ethhdr) + ip_header->ihl*4 + 8);//8代表UDP包头
struct tftphdr *tp = (struct tftphdr *)data; // /usr/include/arpa/tftp.h
tftp_print(data,ntohs(udp_header->len)-8); //ntohs(udp_header->len)-8表示udp数据包长度
}

/*
* Print trivial file transfer program requests
*/
void tftp_print(register const u_char *bp, u_int length)
{
register const struct tftphdr *tp;
register const u_char *p;
register int opcode,i;
static char tstr[] = " [|tftp]";
char buffer[520] = {'\0'};
tp = (const struct tftphdr *)bp;

// printf(" %d", length);
// printf("length of tftp_data = %d\n",length);

/* Print tftp request type */

opcode = EXTRACT_16BITS(&tp->th_opcode);
printf(" %s",tok2str(op2str, "tftp-#%d", opcode));
/* Bail if bogus opcode */

switch (opcode) {

case RRQ:
break;

case WRQ:
break;

case ACK:
break;

case DATA:
break;

case ERROR:
break;

default:
/* We shouldn't get here */
printf("(unknown #%d)", opcode);
break;
}
return;
}

详细的可以查看tcpdump的源码。

小议回车和换行

最近写一个网络分析的玩意,用RAW_SOCKET从网卡上面直接取出数据帧,然后解析,为了就是找出tftp包。解析到数据内容的时候,把数据写出到文件里面,是用fprintf()直接写进去的,结果发现每次自己生成的文件都比原来的文件大。比如原文件是100bytes,获取到的文件可能是108字节。

先用diff 查看,发现竟然每行都显示不同,可是我进去vim编辑的时候,看上去都是一样的。

 hexdump  -C 查看,总算知道不一样的地方了。

linux上都是以‘\n’来表示换行的,ascii码是0A,表示LR,netascii表示数据都是以成行的ASCII码字符组成的,以两个字节---回车字符后换行(CR/LF,0D/0A)表示行结束。这两个行结束的字符在这种格式和本地主机使用的行定界之间进行转化。而octet则将数据看作8bit一组的字节流而不做解释。

linux下RAW SOCKET

raw socket,即原始套接字,可以接收本机网卡上的数据帧或者数据包,对与监听网络的流量和分析是很有作用的.一共可以有3种方式创建这种socket

1.socket(AF_INET, SOCK_RAW, IPPROTO_TCP|IPPROTO_UDP|IPPROTO_ICMP)发送接收ip数据包

2.socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))发送接收以太网数据帧

3.socket(AF_INET, SOCK_PACKET, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))过时了,不要用啊

理解一下SOCK_RAW的原理, 比如网卡收到了一个 14+20+8+100+4 的udp的以太网数据帧.

- 阅读剩余部分 -

NFS 搭建

最近做嵌入式开发的时候,需要NFS加载文件系统,顺便搭建了一个NFS。

NFS:Network File System


功能也就是能把远程网络的文件挂载到NFS Server上,在Server上看来,客户端的挂载的目录就像自己的子目录一样,可以对它操作。所以,对于嵌入式系统的调试是很方便的。

NFS支持的功能很多,所以对应的端口号是不固定的,是随机分配的,但都是小于1024。那么客户机是怎么连接到NFS Server上去的呢?这里有一个RPC的东西来支持。

RPC:(Remote Procedure Call Protocol)


远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息的到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。
RPC在NFS搭建过程钟的功能就是在Server上分配端口号,可以让客户端能从远程连接上Server。RPC固定采用111端口监听。

- 阅读剩余部分 -

字节序

今晚网络编程的时候又碰到了字节序的问题,这次可能要在嵌入式上开发,所以得小心点。

对于0X12345678来存储

大端模式:比较符合直观(地址从左到右增加,数据高位到地位写过去就行)


地址 : 00 01 02 03

数据 : 12 34 56 78

小段模式:比较符合逻辑(低地址存低位,高字节存高位)


地址 : 00 01 02 03

数据:78 56 34 12

拿个IP地址传输来说:


IP : 106.187.89.255

0X : 6a : bb : 59 :e1

在小端模式CPU(X86的都是)下:


地址:00 01 02 03

数据:e1:59:bb:6a

转化成网络字节序,填充到IP头里面:


地址:00 01 02 03

数据:6a:bb:59:e1

传输过程:    0~7 bit, 8 ~ 15 bit,16 ~ 23 bit, 24 ~ 31 bit

传输中数据:   6a      ,    bb        ,       59       ,       e1

接收方


接收过程也是先来先服务(数据链路层也存在传输误码率的控制,这里不考虑丢包,重传之类的了)

那么接收方(假设也是小端)得到数据要是不通过字节序转化(此时还是网络字节序):

地址:00 01 02 03

数据:6a:bb:59:e1

这个时候IP就是就是e1.59.bb.6a,点分十进制就是225.89.187.106。

所以可以用inet_ntoa()进行字节序和字符串转换。

RIP Protocol Limitations and Problems--<转>

The simplicity of the Routing Information Protocol is often given as the main reason for its popularity; I certainly have mentioned this enough times in this section. Simplicity is great most of the time, but an unfortunate “price” of simplicity in too many cases is that problems crop up, usually in unusual cases or special situations. And so it is with RIP: the straight-forward distance-vector algorithm and operation mechanism work well most of the time, but they have some important weaknesses. We need to examine these problems to understand both the limitations of RIP and some of the complexities that have been added to the protocol to resolve them.

- 阅读剩余部分 -

Vlan中Trunk封装方式

VLAN是为解决以太网的广播问题和安全性而提出的一种协议。引入VLAN后,各VLAN内的主机跨交换机进行通信。为了标识各数据帧属于哪一个VLAN,需要对数据帧进行打标(tag)封装,即在以太网帧的基础上增加了VLAN头,用VLAN ID把用户划分为更小的工作组,限制不同工作组间的用户二层的访问,每个工作组就是一个虚拟局域网。目前交换机支持的打标封装协议有IEEE802.1Q和ISL。其中IEEE802.1Q是经过IEEE认证的对数据帧附加VLAN识别信息的协议,属于国际标准协议,适用于各个厂商生产的交换机;而ISL是Inter Switch Link的缩写,是Cisco系列交换机支持的一种与IEEE802.1Q类似的协议。两者互不兼容,ISL是Cisco独有的协议,只能用于Cisco网络设备之间的互联。

- 阅读剩余部分 -

网络中硬件设备简介

看了一段时间的网络,我才发现我连一些基本的硬件设备都不是很清楚,都是很朦朦胧胧的概念,趁这里做一些相关的笔记看,巩固下。

传输介质


直通线(Straight-through):双绞线两端接入RJ-45(水晶头)的线序相同。

交叉线(Crossover):双绞线两端接入RJ-45(水晶头)的线序相反。

- 阅读剩余部分 -

子网划分

前面介绍了IP地址的分类,这里再介绍下子网。子网的出现主要是为了合理的利用IP,减少网络流量。在同一个子网里面,数据的流通是直接通过MAC+ARP进行访问的。但是不同的子网就相当于不同的网段,必须通过三层路由进行转发。这里简单的介绍些,系统的知识很多。子网说简单点,就是把IP地址的主机位借走几位当作网络位,那么就可以隔离出更多的小网络,每个小网络有自己的通信。举个例子,假设一个公司使用的IP范围是172.16.0.0/16,现在要求划分出13个网络,那么划分的方法是,假设划分N个子网,必须保证2^N >= 13,N=4,就是划分16个子网,这时候N=4本来是主机位,但是被网络位借走了,172.16.0.0/20,主机位变成了12位子(2^12-2个节点肯定是绰绰有余的)。前面介绍了主机位全为0的就是网络号,而主机位全为1的就是网段的广播地址。

- 阅读剩余部分 -

交换机配置基本命令

平安夜晚上决定写篇博客,最近要期末考试了,一个学期落下的课程每天都得补,但是趁着杰哥在,我学习 了下实验室的锐捷的设备,主要是交换机和路由的配置。只学了两个下午,所以就大概记录下学到的东西。

首先是vlan技术:VLAN(虚拟局域网)是对连接到的第二层交换机端口的网络用户的逻辑分段,不受网络用户的物理位置限制而根据用户需求进行网络分段。一个VLAN可以在一个交换机或者跨交换机实现。VLAN可以根据网络用户的位置、作用、部门或者根据网络用户所使用的应用程序和协议来进行分组。上面是百度百科上的一些话,简而言之,用vlan技术能划分不同的网络(就算接在同一交换机上的),而且可以使其通信。下面是一些基本的命令的记录:

- 阅读剩余部分 -