Total Pageviews

Friday 9 December 2011

TCP/IP编程的几种有趣的模式


1 使用原始IP数据包,避免针对TCP数据包的过滤

windows xp 和 windows server提供了直接针对原始数据包编程的接口,我们可以在此基础上设计自己的类TCP和UDP协议。
例如我们开发后台监控程序或者希望能够穿透针对TCP数据包的过滤的防火墙。

2 发送数据包和接收数据包使用不同线程,提高网络吞吐量

使用TCP协议,客户端和服务端难以避免需要进行三次握手,数据传输过程中还需要进行确认。这些通信过程都是同步的。
虽然我们可以使用多线程,但是仍面临windows系统最大线程数的限制。
因此对于许多类似于扫描端口,扫描ftp目录内容,搜索内容等连接并发数比较大的任务。一种合理的解决方案是使用一个发送线程发送请求数据包。使用一个接收线程监听某一特定端口监听,接收数据包。
值得注意的是如果直接使用Windows的TCP协议包,发送TCP数据包后线程会进入堵塞状态,因此我们要使用原始的IP数据包实现自定义的 TCP数据包,构建一个TCP数据包,修改TCP数据包的首部。把源端口设置为接收线程监听的端口。发送数据之后随即断开连接,处理下一个请求。
TCP数据包的首部结构如下:

typedef struct tcphdr //定义TCP首部
{
USHORT th_sport; //16位源端口
USHORT th_dport; //16位目的端口
UINT th_seq; //32位序列号
UINT th_ack; //32位确认号
UCHAR th_lenres; //4位首部长度/6位保留字
UCHAR th_flag; //6位标志位
USHORT th_win; //16位窗口大小
USHORT th_sum; //16位校验和
USHORT th_urp; //16位紧急数据偏移量
}TCPHEADER;

关于具体如何使用原始IP数据包,我会在后面另写文章加以说明。

3 使用监听所有IP数据包实现类似wincap的监听功能

实际上就是一个ip数据包接收的服务器,不过可以使用设置SOCK_RAW为SIO_RCVALL,以便接收所有的IP包。

WSADATA wsad;
WSAStartup(MAKEWORD(2,0),&wsad);

//建立socket监听数据包
sock = socket(AF_INET,SOCK_RAW,IPPROTO_IP);
sniff.sin_family = AF_INET;
sniff.sin_port = htons(0);
sniff.sin_addr.s_addr = inet_addr(pinfo->sourceIP);
//绑定到本地随机端口
if(bind(sock,(PSOCKADDR)&sniff,sizeof(sniff)))
return 1;
...................
//设置SOCK_RAW为SIO_RCVALL,以便接收所有的IP包
WSAIoctl(sock, SIO_RCVALL, &dwBufferInLen, sizeof(dwBufferInLen),
&dwBufferLen, sizeof(dwBufferLen), &dwBytesReturned, NULL, NULL);

No comments:

Post a Comment