加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

原始套接字

(2012-12-20 01:16:34)
标签:

365

分类: IT世界任我游

原始套接字是一种底层技术,它工作在网络层,利用原始套接字可以完成如下:

1、设置网卡为混杂模式,嗅探当前网络流经本网卡的所有数据包

2、构造各种数据包(IP,ICMP,TCP,UDP),并进行发送

3、进行新协议的验证

原始套接字是一种更底层的套接字技术,它与流式或者数据包套接字在功能上有很大的不同。流式/数据包套接字只能提供传输层及传输层以上的编程服务,而原始套接字可以提供上至应用层,下至链路层的编程服务。

 

原始套接字技术的灵活性较强,功能强大,甚至可以用它开发整个TCP协议。

 

一、创建

       int rawsock=socket(AF_INET,SOCK_RAW,htons(ETH_P_IP));

 

二、数据发送

在发送之前要调用setsocketopt函数进行套接字的首部设定

       int opt;

       setsocketopt(sockfd,IPPRPTO_IP,IP_HDRINCL,&opt,sizeof(opt));

数据包的发送一般调用sendto函数,但在实际编程实现中要遵循以下规则:

1、若没有调用connect()函数绑定对方地址,则可以调用sendto()函数进行数据包发送

2、若调用connect()函数绑定了对方的地址,则要使用write()send()函数执行发送操作

 

三、数据接收

一般使用recvfrom()函数,但在接收时注意以下细节:

1、获得传输层数据

对于传输层(TCPUDP)产生的IP包,Linux内核不会将它传递给原始套接字,而只是将这些数据包交给对应的应用程序。因此若想通过原始套接字获得传输层的数据,需要设置套接字属性,即在创建原始套接字时,将第三个参数htons置为ETH_P_IP

2、获得网络层数据

对于ICMPIP层数据包,Linux内核不论是否有已经工作的应用程序处理这些报文,都会将此类数据包复制一份交与该协议类型相同的原始套接字

若想获得特定协议的网络层数据报文,可以设置原始套接字中的第三个参数为相应的协议类型

3、本地地址绑定

如果原始套接字调用bind()函数绑定了一个地址,则Linux内核只会将目的地址为绑定地址的数据包传递给原始套接字

4、远程地址绑定

如果原始套接字调用了connect()函数,则Linux内核只会将源地址与connect()函数地址相同的数据包传递给原始套接字

5、协议不识别数据包的处理

对于无法识别协议类型的数据包,Linux内核会尝试将该报文复制一份交由与其协议号相同的元式套接字处理,否则会丢弃该报文,同时向源主机发送主机不可达的ICMP报文

6、其他

若原始套接字没有调用bind()connect()函数,则Linux内核会将所有与协议匹配的IP数据包传递给原始套接字

 

 

设置套接字属性

函数名:setsocketopt

头文件:#include <sys/socket.h>

参数表:int sockfd                            要设置的目的套接字,即设置这个套接字

int level                        套接字的控制层次

int optname                  套接字选项名称

const void *optval         设置的套接字选项,根据选项的名称进行转换

socklen_t *optlen          套接字选项的大小

返回值:int                               若执行成功,则返回0;否则根据返回值判断失败的原因

 

 

setsockopt()函数用于任意类型、任意状态套接口的设置选项值。尽管在不同协议层上存在选项,但本函数仅定义了最高的“套接口”层次上的选项。选项影响套接口的操作,诸如加急数据是否在普通数据流中接收,广播数据是否可以从套接口发送等等。

 有两种套接口的选项:一种是布尔型选项,允许或禁止一种特性;另一种是整形或结构选项。允许一个布尔型选项,则将optval指向非零整形数;禁止一个选 optval指向一个等于零的整形数。对于布尔型选项,optlen应等于sizeof(int);对其他选项,optval指向包含所需选项的整形数 或结构,而optlen则为整形数或结构的长度。SO_LINGER选项用于控制下述情况的行动:套接口上有排队的待发送数据,且closesocket()调用已执行。参见closesocket()函数中关于SO_LINGER选项对closesocket()语义的影响。应用 程序通过创建一个linger结构来设置相应的操作特性:

 struct linger {

 int l_onoff;

 int l_linger;

 };

 为了允许SO_LINGER,应用程序应将l_onoff设为非零,将l_linger设为零或需要的超时值(以秒为单位),然后调用setsockopt()。为了允许SO_DONTLINGER(亦即禁止SO_LINGER),l_onoff应设为零,然后调用setsockopt()

 缺省条件下,一个套接口不能与一个已在使用中的本地地址捆绑(参见bind())。但有时会需要“重用”地址。因为每一个连接都由本地地址和远端地址的组 合唯一确定,所以只要远端地址不同,两个套接口与一个地址捆绑并无大碍。为了通知WINDOWS套接口实现不要因为一个地址已被一个套接口使用就不让它与 另一个套接口捆绑,应用程序可在bind()调用前先设置SO_REUSEADDR选项。请注意仅在bind()调用时该选项才被解释;故此无需(但也无 害)将一个不会共用地址的套接口设置该选项,或者在bind()对这个或其他套接口无影响情况下设置或清除这一选项。

 一个应用程序可以通过打开SO_KEEPALIVE选项,使得WINDOWS套接口实现在TCP连接情况下允许使用“保持活动”包。一个WINDOWS 接口实现并不是必需支持“保持活动”,但是如果支持的话,具体的语义将与实现有关,应遵守RFC1122Internet主机要求-通讯层”中第 4.2.3.6节的规范。如果有关连接由于“保持活动”而失效,则进行中的任何对该套接口的调用都将以WSAENETRESET错误返回,后续的任何调用 将以WSAENOTCONN错误返回。

 TCP_NODELAY选项禁止Nagle算法。Nagle算法通过将未确认的数据存入缓冲区直到蓄足一个包一起发送的方法,来减少主机发送的零碎小数据 包的数目。但对于某些应用来说,这种算法将降低系统性能。所以TCP_NODELAY可用来将此算法关闭。应用程序编写者只有在确切了解它的效果并确实需 要的情况下,才设置TCP_NODELAY选项,因为设置后对网络性能有明显的负面影响。TCP_NODELAY是唯一使用IPPROTO_TCP层的选 项,其他所有选项都使用SOL_SOCKET层。

 如果设置了SO_DEBUG选项,WINDOWS套接口供应商被鼓励(但不是必需)提供输出相应的调试信息。但产生调试信息的机制以及调试信息的形式已超出本规范的讨论范围。

setsockopt()支持下列选项。其中“类型”表明optval所指数据的类型。

 选项        类型   意义

 SO_BROADCAST BOOL 允许套接口传送广播信息。

 SO_DEBUG BOOL 记录调试信息。

 SO_DONTLINER BOOL 不要因为数据未发送就阻塞关闭操作。设置本选项相当于将SO_LINGERl_onoff元素置为零。

 SO_DONTROUTE BOOL 禁止选径;直接传送。

 SO_KEEPALIVE BOOL 发送“保持活动”包。

 SO_LINGER struct linger FAR*   如关闭时有未发送数据,则逗留。

 SO_OOBINLINE BOOL 在常规数据流中接收带外数据。

 SO_RCVBUF int 为接收确定缓冲区大小。

 SO_REUSEADDR BOOL 允许套接口和一个已在使用中的地址捆绑(参见bind())。

 SO_SNDBUF int 指定发送缓冲区大小。

 TCP_NODELAY BOOL 禁止发送合并的Nagle算法。

 

setsockopt()不支持的BSD选项有:

 选项名    类型 意义

 SO_ACCEPTCONN BOOL 套接口在监听。

 SO_ERROR int 获取错误状态并清除。

 SO_RCVLOWAT int 接收低级水印。

 SO_RCVTIMEO int 接收超时。

 SO_SNDLOWAT int 发送低级水印。

 SO_SNDTIMEO int 发送超时。

 SO_TYPE     int 套接口类型。

 IP_OPTIONS    IP头中设置选项。

 

 返回值:

 若无错误发生,setsockopt()返回0。否则的话,返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。

 

 错误代码:

 WSANOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup()

 WSAENETDOWNWINDOWS套接口实现检测到网络子系统失效。

 WSAEFAULToptval不是进程地址空间中的一个有效部分。

 WSAEINPROGRESS:一个阻塞的WINDOWS套接口调用正在运行中。

 WSAEINVALlevel值非法,或optval中的信息非法。

 WSAENETRESET:当SO_KEEPALIVE设置后连接超时。

 WSAENOPROTOOPT:未知或不支持选项。其中,SOCK_STREAM类型的套接口不支持SO_BROADCAST选项,SOCK_DGRAM 类型的套接口不支持SO_DONTLINGER SO_KEEPALIVESO_LINGERSO_OOBINLINE选项。

 WSAENOTCONN:当设置SO_KEEPALIVE后连接被复位。

 WSAENOTSOCK:描述字不是一个套接口。

 

Select技术

Select是一种多路复用IO输入输出模式,在Linux的输入输出编程中也可以用到Select技术,通过Select的轮询机制,发现可用、可读或可写的接口。套接字也是一种输入输出机制,所以可以使用Select这种方式进行高性能的网络程序设计。它是用在非阻塞式的网络应用程序中

server基本流程:

1、创建一个TCP服务套接字

2、设置并绑定本地地址

3、在指定端口监听

4、将服务套接字加入到检测集合

5、将客户端套接字集合中可用的套接字加入到检测集合

6、设置select函数

7、判断当前是否有可读的客户端套接字,若有则读取其中数据,并调用send()函数发送给该客户端

8、若当前有新连接,则加入到客户端套接字集合,若数量过载,则断开本次连接,并发送提示消息“”

9、清空断开的套接字,并转向4

 

 

广播技术

设计广播程序时,要进行套接字的属性设置。另外广播通信要采用UDP的方式,其具体的流程如下。

1、创建UDP套接字

2、设置套接字属性为SO_BROADCAST,即设置程序的广播属性

3、设置广播地址为 INADDR_BROADCAST,同时也要指定发送的端口

4、进行数据的收发操作

服务器端程序流程:

1、创建UDP套接字

2、设置套接字属性为SO_BROADCAST

3、设置本地地址,其中地址为INADDR_BROADCAST,端口为INADDR_ANY

4、绑定本地地址

5、设置广播地址,其中地址为INADDR_BROADCAST,端口为5050(随意指定的)

6、开始收发操作

客户端程序流程:

1、创建UDP套接字

2、设置本地地址,其中地址为INADDR_ANY,端口为5050(服务端指定的)

3、设置套接字属性为地址可重用,即setsocketoptSO_REUSEADDR

4、绑定本地地址

5、开始收发操作

 

 

组播技术

服务器端通过指定一个多播地址,创建一个多播组。

客户端通过指定的多播地址加入多播组

 

 

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有