谁会使用winsock的帮忙加点注释撒 看不懂

genguyige 2011-06-13 10:05:50
#include "winsock2.h"
#include "ws2tcpip.h"
#include <windows.h>
#include<fstream>
#include <iostream>
using namespace std;


#pragma comment(lib, "ws2_32.lib ")


typedef struct _IP_HEADER
{
union
{
BYTE Version;
BYTE HdrLen;
};
BYTE ServiceType;
WORD TotalLen;
WORD ID;
union
{
WORD Flags;
WORD Fragoff;
};
BYTE TimeToLive;
BYTE Protocol;
WORD HdrChksum;
DWORD SrcAddr;
DWORD DstAddr;
BYTE Options;

}IP_HEADER;

int main ()
{
SOCKET sock;
WSADATA wsData;
if (WSAStartup(MAKEWORD(2,2), &wsData) != 0)
{
printf("WSAStartup failed!\n");
return -1;
}
if ( ( sock = socket(AF_INET, SOCK_RAW, IPPROTO_IP) ) == INVALID_SOCKET )
{
printf("create socket failed\n");
return -1;
}
BOOL flag = true;
if ( setsockopt(sock, IPPROTO_IP, IP_HDRINCL,(char*)&flag, sizeof(flag)) == SOCKET_ERROR )
{
printf("setsockopt failed!\n");
return -1;
}
char hostName[128];
if ( gethostname(hostName, 100) == SOCKET_ERROR )
{
printf("gethostname failed!\n");
return -1;
}
hostent* pHostIP;
if( ( pHostIP = gethostbyname(hostName) ) == NULL )
{
printf("gethostbyname failed\n");
return -1;
}
sockaddr_in addr_in;
addr_in.sin_addr = *(in_addr*)pHostIP->h_addr_list[0];
addr_in.sin_family = AF_INET;
addr_in.sin_port = htons(6000);
if ( bind(sock, (PSOCKADDR)&addr_in, sizeof(addr_in)) == SOCKET_ERROR )
{
printf("bind failed\n");
return -1;
}
#define IO_RCVALL _WSAIOW(IOC_VENDOR,1)
DWORD dwBufferLen[10];
DWORD dwBufferInLen = 1;
DWORD dwBytesReturned = 0;
char buffer[100];
if ( WSAIoctl(sock, IO_RCVALL, &dwBufferInLen, sizeof(dwBufferInLen),
&dwBufferLen, sizeof(dwBufferLen), &dwBytesReturned, NULL, NULL) == SOCKET_ERROR )
{
printf("ioctlsocket faild\n");
return -1;
}

printf("开始解析经过本机的IP数据包!\n\n");
int i=0;

while (i<10)
{
i++;
int size = recv(sock, buffer, sizeof(buffer), 0);
IP_HEADER ip = *(IP_HEADER *)buffer;
cout << "-----------------------" << endl;
cout << "版本: " << (ip.Version>>4) << endl;
cout << "头部长度: " << ( (ip.HdrLen & 0x0f) * 4) << endl;

cout << "服务类型: Priority" << (ip.ServiceType >> 5) <<
", Service" << ( (ip.ServiceType >> 1 ) & 0x0f) << endl;
cout << "总长度: " << ip.TotalLen << endl;
cout << "标识符: " << ip.ID << endl;
cout << "标志位: " << ( (ip.Flags >> 15) & 0x01) << ", DF = " <<
( (ip.Flags >> 14) & 0x01) << ", Mf = " << ( (ip.Flags >> 13) &0x01) << endl;
cout << "片偏移: " << (ip.Fragoff & 0x1fff) << endl;
cout << "生存周期: " << (int)ip.TimeToLive << endl;
cout << "协议: Protocol" <<(int)ip.Protocol << endl;
cout << "头部校验和: " << ip.HdrChksum << endl;
cout << "原地址: " << inet_ntoa(*(in_addr *)&ip.SrcAddr) << endl;
cout << "目的IP地址: " <<inet_ntoa(*(in_addr *)&ip.DstAddr) << endl;
}
::closesocket(sock);
::WSACleanup();
return 0;
}


这是一个同学给我的代码让我解释下 我自己是java方向的 看不懂 有会这个的高手帮我加点注释呗 不胜感激 特别是他的工作原理和工作方式
...全文
147 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
ryfdizuo 2011-06-13
  • 打赏
  • 举报
回复
具体函数介绍,msdn上很详细。
genguyige 2011-06-13
  • 打赏
  • 举报
回复

#include "winsock2.h"
#include "ws2tcpip.h"
#include <windows.h>
#include<fstream>
#include <iostream>
using namespace std;

#pragma comment(lib, "ws2_32.lib ")

/*
定义一个数据结构
这个数据结构只有在main方法中使用过 是为了显示方便的

那么经过计算下面在各个结构共占有20个字节
这跟IP地址的头部完全吻合
*/
typedef struct _IP_HEADER
{
union/*共用体表示几个变量共用一个内存位置*/
{
BYTE Version;/*一个字节*/
BYTE HdrLen;/*一个字节*/
};
BYTE ServiceType;/*一个字节*/
WORD TotalLen;/*WORD是short类型的占两个字节*/
WORD ID;/*占两个字节*/
union
{
WORD Flags;/*两个字节*/
WORD Fragoff;/*两个字节*/
};
BYTE TimeToLive;/*一个字节*/
BYTE Protocol;/*一个字节*/
WORD HdrChksum;/*两个字节*/
DWORD SrcAddr;/*四个字节*/
DWORD DstAddr;/*四个字节*/
BYTE Options;/*一个字节*/

}IP_HEADER;

int main ()
{
SOCKET sock;
WSADATA wsData;

//加载winsock库
/*
int PASCAL FAR WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData );
  wVersionRequested Windows Sockets API提供的调用方可使用的最高版本号.高位字节指出副版本(修正)号,低位字节指明主版本号.
*/
/*
#define MAKEWORD(a, b) ((WORD)(((BYTE)(a)) | ((WORD)((BYTE)(b))) << 8)) 这是一个宏定义
从他的定义可以看到他是想通过截断字符来得到结果先得到a的低字节和b的高字节
MAKEWORD(2,2) 输出的结果是514,说明是将前面的2和后面的2组成一个新的WORD。即0000 0010 0000 0010
   而这个结果正是:512 + 2 = 514.
*/

if (WSAStartup(MAKEWORD(2,2), &wsData) != 0)
{
printf("WSAStartup failed!\n");
return -1;
}
// 创建套节字

/*
socket(
int af,
int type,
int protocol
);
以上是这个函数的定义
#endif
af ADDRESS FAMILY 地址族 --》PF_INET, AF_INET: Ipv4网络协议 PF_INET6, AF_INET6: Ipv6网络协议。
type SOCK_STREAM提供面向连接的稳定数据传输,表示流式套接字,即TCP协议;SOCK_RAW表示原始套接字必须有权限才能创建win7不支持
protocol 表示需要得到的数据包的类型

*****所以下面的意思是创建一个IPV4的原始套接字 用于接收任何的IP数据包****
*/
if ( ( sock = socket(AF_INET, SOCK_RAW, IPPROTO_IP) ) == INVALID_SOCKET )
{
printf("create socket failed\n");
return -1;
}
// 设置socket选项

/*
setsockopt(
SOCKET s,
int level,
int optname,
const char FAR * optval,
int optlen
);
#endif
#define IPPROTO_IP 0 dummy for IP
#define IP_HDRINCL 2 /* header is included with data *
*/
BOOL flag = true;
/*
所以下面的含义就是设置socket
*/
if ( setsockopt(sock, IPPROTO_IP, IP_HDRINCL,(char*)&flag, sizeof(flag)) == SOCKET_ERROR )
{
printf("setsockopt failed!\n");
return -1;
}


/*
gethostname(
char FAR * name,
int namelen
);
#endif
*/
/*
返回本地主机的标准主机名。
  int PASCAL FAR gethostname(char FAR *name, int namelen);
  name: 一个指向将要存放主机名的缓冲区指针。
  namelen:缓冲区的长度

该函数把本地主机名存放入由name参数指定的缓冲区中。
返回的主机名是一个以NULL结束的字符串。
主机名的形式取决于Windows Sockets实现-它可能是一个简单的主机名
,或者是一个域名。然而,返回的名字必定可以在gethostbyname()和
WSAAsyncGetHostByName()中使用。


****得到本地主机名
*/
char hostName[128];
if ( gethostname(hostName, 100) == SOCKET_ERROR )
{
printf("gethostname failed!\n");
return -1;
}

/*
返回对应于给定主机名的主机信息。
gethostbyname()返回对应于给定主机名的包含主机名字和地址信息的hostent结构指针。结构的声明与gethostaddr()中一致。
将这些信息存储到pHostIP中这是一个结构体 类容如下

struct hostent {
char FAR * h_name; official name of host
char FAR * FAR * h_aliases; alias list
short h_addrtype; host address type
short h_length; length of address
char FAR * FAR * h_addr_list; list of addresses
#define h_addr h_addr_list[0] address, for backward compat
};
*/

hostent* pHostIP;
if( ( pHostIP = gethostbyname(hostName) ) == NULL )
{
printf("gethostbyname failed\n");
return -1;
}
/* 在sockaddr_in结构中装入地址信息

struct sockaddr_in {
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};

typedef struct in_addr
  {
  union{
  struct
  {
  unsigned char s_b1,s_b2,s_b3,s_b4;
  } S_un_b;
  struct
  {
  unsigned short s_w1,s_w2;
  } S_un_w;
  unsigned long S_addr;
  } S_un;
  } IN_ADDR;

以上的信息我也很多看不懂 一下仅供参考

sin_family指代协议族,在socket编程中只能是AF_INET
  sin_port存储端口号(使用网络字节顺序)
  sin_addr存储IP地址,使用in_addr这个数据结构
  sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。
  s_addr按照网络字节顺序存储IP地址
  sockaddr_in和sockaddr是并列的结构,指向sockaddr_in的结构体的指针也可以指向
  sockaddr的结构体,并代替它。也就是说,你可以使用sockaddr_in建立你所需要的信息,
  然后用进行类型转换就可以了bzero((char*)&mysock,sizeof(mysock));//初始化
  sockaddr_in mysock;
  bzero((char*)&mysock,sizeof(mysock));
  mysock.sa_family=AF_INET;
  mysock.sin_port=htons(1234);//1234是端口号
  mysock.sin_addr.s_addr=inet_addr("192.168.0.1");

此数据结构用做bind、connect、recvfrom、sendto等函数的参数,指明地址信息。
*/

sockaddr_in addr_in;
addr_in.sin_addr = *(in_addr*)pHostIP->h_addr_list[0];
addr_in.sin_family = AF_INET;
addr_in.sin_port = htons(6000);

/*
将一本地地址与一套接口捆绑。本函数适用于未连接的数据报或流类套接口,
在connect()或listen()调用前使用。当用socket()创建套接口后,它便存在
于一个名字空间(地址族)中,但并未赋名。bind()函数通过给一个未命名套
接口分配一个本地名字来为套接口建立本地捆绑(主机地址/端口号)。
*/

if ( bind(sock, (PSOCKADDR)&addr_in, sizeof(addr_in)) == SOCKET_ERROR )
{
printf("bind failed\n");
return -1;
}

/*
下面是定义和宏定义
*/
#define IO_RCVALL _WSAIOW(IOC_VENDOR,1)
DWORD dwBufferLen[10];
DWORD dwBufferInLen = 1;
DWORD dwBytesReturned = 0;


/*
int WSAAPI WSAIoctl(SOCKET s, --> s:一个套接口的句柄。
DWORD dwIoControlCode, -->dwIoControlCode:将进行的操作的控制代码。
LPVOID lpvInBuffer, --> lpvInBuffer:输入缓冲区的地址。
DWORD cbInBuffer,-->cbInBuffer:输入缓冲区的大小。
LPVOID lpvOutBuffer,-->lpvOutBuffer:输出缓冲区的地址。
DWORD cbOutBuffer, -->cbOutBuffer:输出缓冲区的大小。
LPDWORD lpcbBytesReturned,-->lpcbBytesReturned:输出实际字节数的地址。
   LPWSAOVERLAPPED lpOverlapped,-->lpOverlapped:WSAOVERLAPPED结构的地址。
   LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine-->lpCompletionRoutine:一个指向操作结束后调用的例程指针。
);
  
  返回值:
  调用成功后,WSAIoctl ()函数返回0。否则的话,将返回INVALID_SOCKET错误,应用程序可通过WSAGetLastError()来获取相应的错误代码。
*/

if ( WSAIoctl(sock, IO_RCVALL, &dwBufferInLen, sizeof(dwBufferInLen),
&dwBufferLen, sizeof(dwBufferLen), &dwBytesReturned, NULL, NULL) == SOCKET_ERROR )
{
printf("ioctlsocket faild\n");
return -1;
}

printf("开始解析经过本机的IP数据包!\n\n");
/*
该程序运行之后将会一直监控主机上与任何外部的通信并打印出信息
*/
char buffer[100];
int i=0;
while (i<6) //打印信息
{
i++;

/*
从一个套接口接收数据。
  #include <winsock.h>
  int PASCAL FAR recv( SOCKET s, char FAR* buf, int len, int flags);
  s:一个标识已连接套接口的描述字。
  buf:用于接收数据的缓冲区。
  len:缓冲区长度。
  flags:指定调用方式。

本函数用于已连接的数据报或流式套接口s进行数据的接收。并存储在buffer这个数组中

然后将这个buffer直接转化成一个这样的数据结构的变量 那么为什么可以这么做呢?
把一个IP数据包的标准格式看一下就能知道个大概了
比如说ip.Version>>4向右移位4位刚好得到了整个数组的最前面四位并输出
后面的夜一样 依次类推可以得到它的整个工作原理了

*/
int size = recv(sock, buffer, sizeof(buffer), 0);
IP_HEADER ip = *(IP_HEADER *)buffer;
cout << "-----------------------" << endl;
cout << "版本: " << (ip.Version>>4) << endl;
cout << "头部长度: " << ( (ip.HdrLen & 0x0f) * 4) << endl;

cout << "服务类型: Priority" << (ip.ServiceType >> 5) <<
", Service" << ( (ip.ServiceType >> 1 ) & 0x0f) << endl;
cout << "总长度: " << ip.TotalLen << endl;
cout << "标识符: " << ip.ID << endl;
cout << "标志位: " << ( (ip.Flags >> 15) & 0x01) << ", DF = " <<
( (ip.Flags >> 14) & 0x01) << ", Mf = " << ( (ip.Flags >> 13) &0x01) << endl;
cout << "片偏移: " << (ip.Fragoff & 0x1fff) << endl;
cout << "生存周期: " << (int)ip.TimeToLive << endl;
cout << "协议: Protocol" <<(int)ip.Protocol << endl;
cout << "头部校验和: " << ip.HdrChksum << endl;
cout << "原地址: " << inet_ntoa(*(in_addr *)&ip.SrcAddr) << endl;
cout << "目的IP地址: " <<inet_ntoa(*(in_addr *)&ip.DstAddr) << endl;
}
// 关闭套接字句柄,结束会话
::closesocket(sock);
::WSACleanup();
return 0;
}




以上是我自己加的注释 请大神不吝赐教
luciferisnotsatan 2011-06-13
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 dizuo 的回复:]

找本网络套接字编程的书看 靠谱点。
[/Quote]
直接查下MSDN也不错。
maoxing63570 2011-06-13
  • 打赏
  • 举报
回复
原始套接字
genguyige 2011-06-13
  • 打赏
  • 举报
回复
好吧 我一句一句看去了
c_losed 2011-06-13
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 genguyige 的回复:]

额 楼上的 能更详细一点吗? 给你加分
[/Quote]
额 我觉得已经很详细了。。。
再详细只能一句句注释了
其实那些你看看API就明白了
bdmh 2011-06-13
  • 打赏
  • 举报
回复
这东西没什么好注释的,都是socket的基本东西,你去看socket的资料就都清楚了
genguyige 2011-06-13
  • 打赏
  • 举报
回复
额 楼上的 能更详细一点吗? 给你加分
c_losed 2011-06-13
  • 打赏
  • 举报
回复
看大体意思就是创建套接字后 分析并显示本地6000端口所收到的信息

socket不熟。。不对请大神指正
c_losed 2011-06-13
  • 打赏
  • 举报
回复

{
SOCKET sock;
WSADATA wsData;

//加载winsock库
if (WSAStartup(MAKEWORD(2,2), &wsData) != 0)
{
printf("WSAStartup failed!\n");
return -1;
}
// 创建套节字
if ( ( sock = socket(AF_INET, SOCK_RAW, IPPROTO_IP) ) == INVALID_SOCKET )
{
printf("create socket failed\n");
return -1;
}
// 设置socket选项
BOOL flag = true;
if ( setsockopt(sock, IPPROTO_IP, IP_HDRINCL,(char*)&flag, sizeof(flag)) == SOCKET_ERROR )
{
printf("setsockopt failed!\n");
return -1;
}
char hostName[128];
if ( gethostname(hostName, 100) == SOCKET_ERROR )
{
printf("gethostname failed!\n");
return -1;
}
hostent* pHostIP;
if( ( pHostIP = gethostbyname(hostName) ) == NULL )
{
printf("gethostbyname failed\n");
return -1;
}
// 在sockaddr_in结构中装入地址信息
sockaddr_in addr_in;
addr_in.sin_addr = *(in_addr*)pHostIP->h_addr_list[0];
addr_in.sin_family = AF_INET;
addr_in.sin_port = htons(6000);
if ( bind(sock, (PSOCKADDR)&addr_in, sizeof(addr_in)) == SOCKET_ERROR )
{
printf("bind failed\n");
return -1;
}
#define IO_RCVALL _WSAIOW(IOC_VENDOR,1)
DWORD dwBufferLen[10];
DWORD dwBufferInLen = 1;
DWORD dwBytesReturned = 0;
char buffer[100];
if ( WSAIoctl(sock, IO_RCVALL, &dwBufferInLen, sizeof(dwBufferInLen),
&dwBufferLen, sizeof(dwBufferLen), &dwBytesReturned, NULL, NULL) == SOCKET_ERROR )
{
printf("ioctlsocket faild\n");
return -1;
}

printf("开始解析经过本机的IP数据包!\n\n");
int i=0;

while (i<10) //打印信息
{
i++;
int size = recv(sock, buffer, sizeof(buffer), 0);
IP_HEADER ip = *(IP_HEADER *)buffer;
cout << "-----------------------" << endl;
cout << "版本: " << (ip.Version>>4) << endl;
cout << "头部长度: " << ( (ip.HdrLen & 0x0f) * 4) << endl;

cout << "服务类型: Priority" << (ip.ServiceType >> 5) <<
", Service" << ( (ip.ServiceType >> 1 ) & 0x0f) << endl;
cout << "总长度: " << ip.TotalLen << endl;
cout << "标识符: " << ip.ID << endl;
cout << "标志位: " << ( (ip.Flags >> 15) & 0x01) << ", DF = " <<
( (ip.Flags >> 14) & 0x01) << ", Mf = " << ( (ip.Flags >> 13) &0x01) << endl;
cout << "片偏移: " << (ip.Fragoff & 0x1fff) << endl;
cout << "生存周期: " << (int)ip.TimeToLive << endl;
cout << "协议: Protocol" <<(int)ip.Protocol << endl;
cout << "头部校验和: " << ip.HdrChksum << endl;
cout << "原地址: " << inet_ntoa(*(in_addr *)&ip.SrcAddr) << endl;
cout << "目的IP地址: " <<inet_ntoa(*(in_addr *)&ip.DstAddr) << endl;
}
// 关闭套接字句柄,结束会话
::closesocket(sock);
::WSACleanup();
return 0;
}
genguyige 2011-06-13
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 dizuo 的回复:]

找本网络套接字编程的书看 靠谱点。
[/Quote]

我没时间啊。。
ryfdizuo 2011-06-13
  • 打赏
  • 举报
回复
找本网络套接字编程的书看 靠谱点。

69,373

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧