最近学习了完成端口编程模型,即IOCP,看了书上写的TCP服务端,就想写个TFTP服务端练练手,一方面因为TFTP是比较简单的协议,另一方面对完成端口的熟悉.
完成端口:
完成端口基本上公认为一种在windows服务平台上比较成熟和高效的IO方法,用完成端口进行重叠I/O的技术在WindowsNT和WIndows2000上提供了真正的可扩展性。完成端口和Windows Socket2.0结合可以开发出支持大量连接的网络服务程序。使用起来还是很简单的,调用CreateIoCompletionPort既可以创建完成端口也可以将套接字与完成端口对象相关联,然后所有在完成端口上关联的套接字上读和写的操作的完成都反应到了完成端口上TFTP:TFTP类似FTP,不过它比FTP简单的多了,也少了安全的认证,适用于小型文件的传输,关于它的详细信息可以百度搜索下对应的RFC文件说明,附件中也有.| Opcode | Filename | 0 | Mode | 0 |  
这是个简单的TFTP报文结构,Mode字段是模式,我的服务端只支持2进制模式,这也是普遍的格式。程序的基本思想是创建1个监听线程和N个工作线程,监听线程负责启动工作线程,和处理超时重发机制,最后结束工作线程。工作线程负责从完成端口取出数据 ,并根据读和写操作的完成来具体做些处理。对于每个客户端则创建一个套接字并申请一个CIOCPContext来描述它,对于发送和接收每个数据包 用一个CIOCPBuffer来描述 ,具体定义见代码

几个感觉有点难度的方面:1.在判断一个数据包是属于哪个CIOCPContext的时候,起初是在CIOCPBuffer中加入了对应的Context指针,但后来发现这样的逻辑是有问题的,比如你在客户端的socket1,和socket2上都投递了读请求,这时候向socket2发送的数据来了,但这时候完成端口它是分不清的,可能的结果是它满足了socket1的读请求,这就导致了context指针不正确,所以我是这样解决

代码:
        //read操作完成后的Context是不正确的需要修正        memcpy(&addrFrom ,(pBuffer->buff+516) ,sizeof(SOCKADDR));
从完成的读请求BUFF的516偏移处读取源地址  在投递读请求的时候是这样的
代码:
::WSARecvFrom(m_sListen, &buf, 1, &dwBytes, &dwFlags ,(SOCKADDR*)(pBuffer->buff+516) ,&fromlen ,&pBuffer->ol, NULL)
意思是这个请求被完成后会在pBuffer->buff的偏移516字节处得到发送地址,为什么要516字节呢 ? 因为一个TFTP头最多512字节  我空了4个字节方便调试 得到源地址后就好办了,
代码:
pContext = FindCorrectContext(&addrFrom);
  通过FindCorrectContext这个函数在m_connectList中找到对应的Context,这个函数很简单就不引用代码了
2.超时处理方面 ,只对于写操作完成的情况,每次一个写操作完成后,都会将Buffer记录在CIOCPContext结构中的pOutTimeBuffer中,然后通知监听线程进行超时处理,也就是说每次监听线程只能处理一个Buffer的超时工作 ,监听线程会将这个Buffer重新发送一遍 
应该就这2点了  其余的都是些小细节了。。另外我把发送错误信息重新写了个函数PostError,因为根据协议发送过错误信息是不需要得到回应的<br>本工程在VC2008下编译成功 第一次发帖  希望不要被喷的太惨。。另外大四了  卖身找工作啊  白菜价出租 最好南京这边的。。。<br>

tftp协议.rar

TftpServer.rar