Windows下基于原始套接字的回射客户端

来源:互联网 发布:java发送图片 编辑:程序博客网 时间:2024/06/05 07:33

根据使用的场合的不同,我们可以使用TCP、UDP和原始套接字来实现这个功能,今天就说一下基于基于原始套接字的回射客户端源代码。跟前面提过的工程一样,这个工程里面也包含着SocketFrame.cpp和SocketFrame.h这两个文件,所以就在之前的基础上添加使用原始套接字的回射客户端的功能文件就可以了。该功能源代码如下:

// EchoUDPClientRaw.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include "winsock2.h"#include "ws2tcpip.h"#include "stdio.h"#include "SocketFrame.h"#pragma pack(push,1)#defineMAXLINE    200// 发送和接收缓冲区的长度#defineINPUTLINE100// 输入文本的长度 #define ECHOPORT        7210//回射服务器的端口号/********************************************************函数名:UDP_MakeProbePkt输入参数:char *pUDPData:待填充的缓冲区指针,应填充包括IP首部在内的数据          char *pInputData:存储用户输入的字符串          UINT uSrcIP:源IP地址  UINT uDstIP:目的IP地址  USHORT uSrcPort:源端口号  USHORT uDestPort:目的端口号输出参数:构造后的缓冲区有效字节长度。功能:构造UDP协议的回射报文*********************************************************/int UDP_MakeProbePkt(char *pUDPData, char *pInputData, UINT uSrcIP, UINT uDestIP, USHORT uSrcPort, USHORT uDestPort){IPHDR*IPhdr;//基本IP头定义UDPHDR*UDPhdr;//UDP头定义FHDRFhdr;//伪头charbuf[MAXLINE];//数据缓冲char    *data;int     iRet=0;char *lpbuf = buf;CSocketFrame frame;/////////设置IP头ZeroMemory(buf,sizeof(buf));IPhdr=(IPHDR *)pUDPData;IPhdr->version = 4;IPhdr->hdr_len = 5;IPhdr->TOS = 0;IPhdr->TotLen = htons(sizeof(IPHDR)+sizeof(UDPHDR)+strlen(pInputData));IPhdr->ID = (USHORT)GetCurrentThreadId();IPhdr->FlagOff = 0;IPhdr->TTL = 0xff;IPhdr->Protocol = IPPROTO_UDP;IPhdr->Checksum = 0x0;//源地址为本机地址IPhdr->IPSrc = uSrcIP;//目的地址为入参,可能变化IPhdr->IPDst = uDestIP;////////// 构造UDP包UDPhdr=(UDPHDR *)(pUDPData+sizeof(IPHDR));UDPhdr->dst_portno = htons(uDestPort);UDPhdr->src_portno = htons(uSrcPort);UDPhdr->udp_checksum = 0;//UDPhdr->udp_length = htons(sizeof(UDPHDR));data=pUDPData+sizeof(IPHDR)+sizeof(UDPHDR);int ii=strlen(pInputData);memcpy(data,pInputData,strlen(pInputData));UDPhdr->udp_length = htons(sizeof(UDPHDR)+strlen(pInputData));//设置伪头Fhdr.IPDst = IPhdr->IPDst;Fhdr.IPSrc = IPhdr->IPSrc;Fhdr.protocol = IPPROTO_UDP;Fhdr.udp_length = UDPhdr->udp_length;Fhdr.zero = 0x00;//计算UDP校验和//校验和计算范围包括:UDP头,伪首部和用户数据char *ptmp = buf;memcpy(ptmp,&Fhdr,sizeof(Fhdr));ptmp += sizeof(Fhdr);memcpy(ptmp,UDPhdr,sizeof(UDPHDR));ptmp +=sizeof(UDPHDR);memcpy(ptmp,data,strlen(pInputData));UDPhdr->udp_checksum = frame.check_sum((USHORT*)buf,sizeof(Fhdr)+sizeof(UDPHDR)+strlen(pInputData));iRet = sizeof(IPHDR) + sizeof(UDPHDR)+strlen(pInputData);return iRet;}/********************************************************函数名:UDP_Filter输入参数:char *pUDPData:待填充的缓冲区指针,应填充包括IP首部在内的数据          UINT uServerIP:目标IP地址  USHORT uServerPort:目标端口号输出参数:true表示找到回射应答,false表示当前收到的数据报并不是服务器的回射应答。功能:对接收到的数据报进行过滤,获得由回射服务器发回的应答*********************************************************/BOOL UDP_Filter(char *pUDPData, UINT uServerIP,USHORT uServerPort){IPHDR*pIPhdr;//基本IP头定义UDPHDR*pUDPhdr;//UDP头定义char    *pData;UINT uSourceIP;        //接收到包的源IP地址USHORT uSourcePort;       //接收到包的源端口pIPhdr=(IPHDR *)pUDPData;uSourceIP = pIPhdr->IPSrc;pUDPhdr=(UDPHDR *)(pUDPData+sizeof(IPHDR));uSourcePort = ntohs(pUDPhdr->src_portno);pData = pUDPData +sizeof(IPHDR) +sizeof(UDPHDR);if ( pIPhdr->Protocol ==17 && uSourceIP == uServerIP && uSourcePort == uServerPort){//服务器返回的应答        printf("客户端接收到数据:%s \r\n", pData );return true;}elsereturn false;}/********************************************************函数名:UDP_Echo输入参数:SOCKET sockSendRaw:用于发送UDP报文的原始套接字          SOCKET sockRecvRaw:用于接收响应的原始套接字  UINT uSrcIP:源IP地址  UINT uDstIP:目的IP地址  USHORT uSrcPort:源端口号  USHORT uDestPort:目的端口号输出参数:0:成功,1:失败功能:回射客户端的具体功能函数*********************************************************/BOOL UDP_Echo(SOCKET sockSendRaw,SOCKET sockRecvRaw, UINT uSrcIP,UINT uDstIP,USHORT uSrcPort,USHORT uDestPort){//初始化参数SOCKADDR_IN  saDest;int          len; int          iResult=0;int          bResult=FALSE;//申请缓冲区    char sendline[MAXLINE],recvline[MAXLINE],inputline[INPUTLINE];memset(sendline,0,MAXLINE);memset(recvline,0,MAXLINE);    memset(inputline,0,INPUTLINE);//设置目的地址memset(&saDest,0 ,sizeof(saDest));saDest.sin_family = AF_INET;saDest.sin_addr.s_addr = uDstIP;//构造分析数据报文//循环发送用户的输入数据,并接收服务器返回的应答,直到用户输入"Q"结束fflush(stdin);gets_s(inputline,INPUTLINE);if( *inputline == 'Q'){printf("input end!\n");return 0;}while(strlen(inputline)!=0){    len = UDP_MakeProbePkt(sendline, inputline, uSrcIP,uDstIP,uSrcPort,uDestPort);//发送回射请求iResult = sendto(sockSendRaw,sendline,len,0,(SOCKADDR *)&saDest,sizeof(saDest));if(iResult == SOCKET_ERROR){printf("sendto 函数调用错误,错误号: %ld\n", WSAGetLastError());return 1;}printf("\r\n客户端发送%d字节数据\r\n", iResult);    memset(recvline,0,MAXLINE);while((iResult = recvfrom( sockRecvRaw, recvline, MAXLINE, 0, NULL, NULL )) >0){//过滤出来自服务器端点地址的UDP回射应答并显示bResult = UDP_Filter(recvline,uDstIP,uDestPort);if( bResult == TRUE ) break;else{ memset(recvline,0,MAXLINE); continue;}}if (iResult == SOCKET_ERROR){         printf("recvfrom 函数调用错误,错误号: %d\n", WSAGetLastError());}//接收新的回射内容memset(sendline,0,MAXLINE);memset(inputline,0,INPUTLINE);printf("\n请输入回射字符串:");fflush(stdin);    gets_s(inputline,INPUTLINE);if( *inputline == 'Q'){printf("input end!\n");return 0;}}return iResult;}int main(int argc, char* argv[]){CSocketFrame frame;    int iResult;SOCKET sockSendRaw,sockRecvRaw;sockaddr_in localaddr;//初始化参数if (argc != 2)    {fprintf(stderr,"\nUsage: EchoUDPClientRaw ***.***.***.***\n");return 0;    }//Windows Sockets Dll初始化frame.start_up();//创建原始套接字,并设置相应的选项sockSendRaw = frame.raw_socket( TRUE, FALSE, IPPROTO_IP, NULL);if ( sockSendRaw == 0 )return -1;    sockRecvRaw = frame.raw_socket( FALSE, TRUE, IPPROTO_IP, &localaddr);if ( sockRecvRaw == 0 )return -1;printf("套接字创建成功\n请输入回射字符串:");//开始回射请求的发送与接收//发送从构造IP头开始的UDP数据包,接收过滤,输出结果iResult = UDP_Echo( sockSendRaw,sockRecvRaw, localaddr.sin_addr.S_un.S_addr ,inet_addr(argv[1]),ECHOPORT, ECHOPORT);if ( iResult ==1 )        printf("回射过程出错!\n");//结束socket,释放资源iResult = closesocket(sockSendRaw);    if (iResult == SOCKET_ERROR){        printf("closesocket 函数调用错误,错误号:%d\n", WSAGetLastError());        return 1;    }    frame.quit( sockRecvRaw );return iResult;}


0 0
原创粉丝点击