我想编一个网络扫描器,使用了Winsock
for(ip=开始IP;ip<结束IP;i++)
{
try
sock.connect(ip);
记录IP地址
except
记录错误原因;
sock.close;
^^^^^^^^
}
问题是sock.close();好像并不能真正的关闭sock连接
用netstat -n可以看到大量处于TIME_WAIT状态的正在关闭的socket连接,
而且连接关闭要等很久,而程序又在不停的connect,每次都出来一个新的socket连接
netstat -s也显示TCP的活动连接越来越多
如果扫描的ip很多的话,过不了多久就出现
socket error 10055
No buffer space is available.
我该怎么办?
可不可以有哪个api函数能得到正在打开的sock的数量,然后在程序中限制使打开的socket不至于太多。
真搞不懂那些商业扫描器是怎么做的?
for(ip=开始IP;ip<结束IP;i++)
{
try
sock.connect(ip);
记录IP地址
except
记录错误原因;
sock.close;
^^^^^^^^
}
问题是sock.close();好像并不能真正的关闭sock连接
用netstat -n可以看到大量处于TIME_WAIT状态的正在关闭的socket连接,
而且连接关闭要等很久,而程序又在不停的connect,每次都出来一个新的socket连接
netstat -s也显示TCP的活动连接越来越多
如果扫描的ip很多的话,过不了多久就出现
socket error 10055
No buffer space is available.
我该怎么办?
可不可以有哪个api函数能得到正在打开的sock的数量,然后在程序中限制使打开的socket不至于太多。
真搞不懂那些商业扫描器是怎么做的?
解决方案 »
- socket通过HTTP代理连接服务器问题
- CFileDialog,如何把上面的打开等按钮的文本改成别的字?
- 如何在CDateTimeCtrl和CComboBox的属性为disable改变背景色和字体颜色,在线等待
- 请教!!已知另一进程的窗口句柄,如何获得这个窗口上combo box控件的选择内容?
- VC中的文件输出问题!!
- 关于限制应用程序开启两次的问题
- 深入MFC,CRichEditView/CCtrlView为何要拦截OnPaint?
- MoveLast的问题
- To XT2大兄:
- 为什么我接不到我的自定义消息????
- AT+CMGR=index为什么取不到手机短信息?
- 请告知"学习回调函数"的文章或书?
试试先shutdown
另外如果一个socket没有连接成功,可以继续使用的
异步方式是不是要有一个窗口支持啊?
::::就是那个 SO_REUSEADDR
有没有完整一点的代码?
=fly by=
LPHOSTENT ScanIPAddr(DWORD dwIP)
{
SOCKET sock = INVALID_SOCKET;
LPHOSTENT lphost = NULL;
SOCKADDR_IN server;
u_long ul = 1;
struct timeval timeout ;
fd_set r; memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = _nPort;
server.sin_addr.s_addr = htonl((u_long)dwIP); sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sock == INVALID_SOCKET)
return NULL; //设置非阻塞方式连接
if(ioctlsocket(sock, FIONBIO, (u_long*)&ul)==SOCKET_ERROR)
return NULL; if(0 != connect(sock, (SOCKADDR*)&server, sizeof(server)))
{
if(WSAGetLastError() != WSAEWOULDBLOCK)
{
closesocket(sock);
return NULL;
}
} //select 模型,即设置超时
FD_ZERO(&r);
FD_SET(sock, &r);
timeout.tv_sec = 0; //连接超时0秒
timeout.tv_usec = 700;
if(select(0, 0, &r, 0, &timeout) <= 0)
{
closesocket(sock);
return NULL;
} lphost = gethostbyaddr((const char *)&(server.sin_addr), 4, AF_INET);
closesocket(sock); return lphost;
}
setsockopt(Server,SOL_SOCKET,SO_REUSEADDR,(LPCSTR)&val,4);
就是那个SO_REUSEADDR
如何使用?用在什么地方?
{
public:
virtual void ConnectionCompletionSucceeded(
SOCKET connectedSocket,
int index,
unsigned int remoteAddress,
unsigned short remotePort,
DWORD data
) = 0; virtual void ConnectionCompletionFailed(
int index,
DWORD dwErrorCode,
unsigned int remoteAddress,
unsigned short remotePort,
DWORD data
) = 0; virtual void ConnectionRequestCancelResult (
BOOL bSucceeded,
int index,
unsigned int remoteAddress,
unsigned short remotePort,
DWORD data
) = 0;
};
// 最后还有一些宏,用于给一个类进行池方式的分配与释放
// 另外还有一个实现多线程同步的内存池,由于这里不需要, 我就不贴了class SizePool
{
public:
SizePool( int size, int numOfElem = 4)
: elemSize(size), elemPerBlock( numOfElem <= 0 ? 8 : numOfElem )
,mapSize(0) ,allocatedSize(0), pMap(0), freeList(0)
{
freeList = NULL;
bitNum = 0; int num = numOfElem;
int index = 0;
while( !(num & 1) )
{
num >>= 1;
bitNum++;
}
_ASSERTE ( bitNum >= 2);
_ASSERTE ( 1<<bitNum == numOfElem );
bitMask = 0xffffffff >> (32-bitNum);
} void put( void* pMem )
{
Note * temp = freeList;
freeList = (Note*)pMem;
((Note*)pMem)->next = temp;
} void * get() {
if (freeList != NULL)
{
Note * temp = freeList;
freeList = freeList->next;
return temp;
}
else
{
if (mapSize * elemPerBlock <= allocatedSize)
growMap();
int block = (allocatedSize) >> bitNum;
if (pMap[block].rowPointer == NULL)
{
pMap[block].rowPointer = (unsigned char*)malloc(elemSize * elemPerBlock);
_ASSERTE(pMap[block].rowPointer != NULL);
}
return pMap[block].rowPointer + ((allocatedSize++) & bitMask) * elemSize;
}
} ~SizePool()
{
deleteAllMemory();
}private:
void deleteAllMemory()
{
if (NULL != pMap)
{
int block = 0;
for (block=0; block<mapSize; block++)
{
if (pMap[block].rowPointer != NULL)
free(pMap[block].rowPointer);
else
break;
} free( pMap ); this->pMap = NULL;
this->allocatedSize = 0;
this->mapSize = 0;
this->freeList = NULL;
}
} int getElementSize()
{
return (elemSize);
} int getElemPerBlock()
{
return (elemPerBlock);
} template<class T>
static SizePool* CreateSizePool()
{
const int size = (int)(sizeof(T));
if( size <= 32 )
{
return new SizePool( size, 16 );
}
else if( size <= 64 )
{
return new SizePool( size, 8 );
}
else if( size <= 128 )
{
return new SizePool( size, 4 );
} return new SizePool( size, 2 );
} void growMap()
{
int growsize = mapSize / 2;
if( growsize < 8 )
growsize = 8; int newsize = mapSize + growsize; Map* newMap = (Map*)malloc(newsize * sizeof(Map)); Map* p = newMap;
for (int i=0; i<newsize; i++)
{
p[i].rowPointer = NULL;
} memcpy(newMap, pMap, mapSize * sizeof(Map)); free(pMap);
mapSize = newsize;
pMap = newMap;
}private:
typedef struct _Map {
unsigned char* rowPointer;
}Map; typedef struct _Note {
_Note* next;
}Note;
const int elemSize;
const int elemPerBlock; int bitMask;
int bitNum; int mapSize; // pMap 数组的大小
int allocatedSize; // 客户从 SizePool 对象 get 了多少次
int freeListSize; // 自由列表大小 Map* pMap; // Map 数组
Note* freeList; // 自由列表 SizePool()
: elemSize(0), elemPerBlock(0),
mapSize(0), allocatedSize(0), pMap(0), freeList(0)
{
}
};// 帮助宏
// 使用 SizePool 来分配对象
#define DECLARE_POOL_ALLOC(Type) \
private: \
static SizePool _pool; \
public: \
static void* operator new(size_t size) \
{ \
return _pool.get(); \
} \
static void operator delete(void* pMem) \
{ \
if( pMem != NULL ) \
_pool.put( pMem ); \
} \
SizePool * getPoolPointer() { \
return &_pool; \
}#define _IMPLEMENT_POOL_ALLOC( Type, elemPerBlock ) \
rpt::SizePool Type::_pool( sizeof(Type), elemPerBlock );#define IMPLEMENT_POOL_ALLOC( Type ) \
_IMPLEMENT_POOL_ALLOC( Type, 8 );
// 但凡继承自 rpt::ClientSocket::ConnectRequest , 必须实现自己的 new delete 分配方法
// 可以简单的用 DECLARE_POOL_ALLOC, IMPLEMENT_POOL_ALLOC 系列宏重新声明class ClientSocket
{
public:
ClientSocket( BOOL bInit = TRUE );
virtual ~ClientSocket(); int addConnectionRequest( char* pszRemoteAddress, unsigned short remotePort, DWORD data );
int addConnectionRequest( unsigned int remoteAddress, unsigned short remotePort, DWORD data );
int addConnectionRequestN( unsigned int remoteAddress, unsigned short remotePort, DWORD data );
IConnectionCompletion* getIConnectionCompletion(){ return this->pCompletion; }
void setIConnectionCompletion( IConnectionCompletion* p ){ this->pCompletion = p; }
int getPendingConnections() { return (int)pendingRequest.size(); }
void cancelConnectRequest( int index );
void uninitialize();
void initialize(); class ConnectRequest
{
DECLARE_POOL_ALLOC_SYNC( ConnectRequest ); public:
ConnectRequest( unsigned int a, unsigned int p, DWORD d )
: address(a), port(p), data( d )
{ } public:
SOCKET sock;
unsigned int address;
unsigned int port;
int index;
DWORD data; // client data
};private: IConnectionCompletion *pCompletion; HWND window;
HANDLE thread;
unsigned int threadID; deque<ConnectRequest*> sockCache;
vector<ConnectRequest*> pendingRequest; deque<int> availIndex;
CriticalSection lockIndex; BOOL bInitialized;
BOOL bCreateQueue;
HANDLE event; static BOOL bRegistered; static const UINT MIN_SOCKET_INDEX = WM_USER + 10;
static const UINT MAX_SOCKET_INDEX = WM_APP - 1;
static const UINT MAX_SOCKETS = MAX_SOCKET_INDEX - MIN_SOCKET_INDEX -1; static const UINT WM_EXIT_NOTIFY = WM_USER + 1;
static const UINT WM_ADD_CONNECT_NOTIFY = WM_USER + 2;
static const UINT WM_CANCEL_CONNECT_REQUEST = WM_USER + 3; static const char* const CLIENT_SOCKET_WINDOW_CLASS_NAME; unsigned int MessageLoop(void);
int getIndex( );
void putIndex( int i );
void growAvailSocketIndex();
static LRESULT CALLBACK WindowProc( HWND hwnd, UINT msg, WPARAM w, LPARAM l);
static unsigned int __stdcall BeginWork( void * p );
};_IMPLEMENT_POOL_ALLOC_SYNC( rpt::ClientSocket::ConnectRequest, 8 );
BOOL ClientSocket::bRegistered = FALSE;
const char* const ClientSocket::CLIENT_SOCKET_WINDOW_CLASS_NAME = "RPT_CLIENTSOCKET";int ClientSocket::addConnectionRequest(
char* pszRemoteAddress, unsigned short remotePort, DWORD data )
{
return addConnectionRequestN( inet_addr(pszRemoteAddress), htons(remotePort), data );
}int ClientSocket::addConnectionRequest(
unsigned int remoteAddress, unsigned short remotePort, DWORD data)
{
return addConnectionRequestN( htonl(remoteAddress), htons(remotePort), data );
}void ClientSocket::cancelConnectRequest( int index )
{
if (bInitialized)
{
_ASSERTE( IsWindow( this->window) );
PostThreadMessage( threadID, WM_CANCEL_CONNECT_REQUEST, index, 0 );
}
}void ClientSocket::initialize()
{
if( bInitialized )
return; if( thread != NULL )
CloseHandle( thread ); event = CreateEvent( NULL, FALSE, FALSE, NULL );
_ASSERTE( event ); thread = (HANDLE)_beginthreadex(
NULL,
0,
ClientSocket::BeginWork,
this,
0,
&threadID
); _ASSERTE( thread != NULL ); WaitForSingleObject( event, INFINITE );
CloseHandle( event );
event = NULL; bInitialized = TRUE;
}void ClientSocket::growAvailSocketIndex()
{ int oldsize = (int)pendingRequest.size(); if (oldsize < MAX_SOCKETS)
{
int newsize = oldsize * 2;
if (newsize == 0)
{
newsize = 8;
}
else if (newsize > MAX_SOCKETS)
{
newsize = MAX_SOCKETS;
} pendingRequest.resize( newsize, NULL ); while (oldsize < newsize)
availIndex.push_back( oldsize++ );
}
}
void ClientSocket::uninitialize()
{
if (!bInitialized)
return; _ASSERTE( IsWindow(window) );
bInitialized = FALSE; PostThreadMessage( threadID, WM_EXIT_NOTIFY, 0, 0 );
WaitForSingleObject( thread, 1000 * 60 * 10 );
}
ClientSocket::~ClientSocket()
{
uninitialize();
if (thread != NULL)
{
CloseHandle( thread );
thread = NULL;
}
}
void ClientSocket::putIndex( int i )
{
_ASSERTE( i >= 0 && i < MAX_SOCKET_INDEX - MIN_SOCKET_INDEX); lockIndex.lock(); availIndex.push_back( i ); lockIndex.unlock();
}
int ClientSocket::getIndex()
{ lockIndex.lock(); if (availIndex.size() == 0)
{
growAvailSocketIndex();
} if (availIndex.size() == 0)
{
lockIndex.unlock();
return -1;
} int ret = availIndex.back();
_ASSERTE( ret >= 0 && ret < MAX_SOCKET_INDEX - MIN_SOCKET_INDEX );
availIndex.pop_back(); lockIndex.unlock();
return ret;
}int ClientSocket::addConnectionRequestN(
unsigned int remoteAddress,
unsigned short remotePort,
DWORD data)
{ ConnectRequest* rs = new ConnectRequest( remoteAddress, remotePort, data); if (!bInitialized)
{
delete rs;
return -1;
} rs->index = getIndex();
if( -1 == rs->index )
{
delete rs;
return -1;
} if (FALSE == PostThreadMessage( this->threadID, WM_ADD_CONNECT_NOTIFY, (WPARAM)rs, 0 ))
// if( FALSE == PostMessage( this->window, WM_ADD_CONNECT_NOTIFY, (WPARAM)rs, 0 ) )
{
putIndex( rs->index );
delete rs;
return -1;
} _ASSERTE( IsWindow( this->window ) );
return rs->index;
}
LRESULT CALLBACK ClientSocket::WindowProc( HWND hwnd, UINT msg, WPARAM w, LPARAM l)
{
ClientSocket* pthis = NULL; switch( msg )
{ case WM_CREATE:
SetWindowLong( hwnd, 0, (LONG)(LONG_PTR)((LPCREATESTRUCT)l)->lpCreateParams );
return 0; // 阻止关闭窗口操作
case WM_CLOSE:
return 0; case WM_QUERYENDSESSION: break;
//return ((ClientSocket*)GetWindowLong(hwnd, 0 ))-> case WM_ENDSESSION:
break; case WM_DESTROY:
//((ClientSocket*)GetWindowLong(hwnd, 0 ))->uninitialize();
break;
} return DefWindowProc( hwnd, msg, w, l );
}
{
MSG msg;
HWND hwnd = this->window;
int error;
sockaddr_in addr;
addr.sin_family = AF_INET;
ConnectRequest* rs;
ConnectRequest* rs2;
size_t cacheSize = 0;
// SOCKET sock; while( true )
{
GetMessage( &msg, NULL, 0, 0 ); _ASSERTE( IsWindow(hwnd) ); if( msg.message >= MIN_SOCKET_INDEX && msg.message <= MAX_SOCKET_INDEX )
{
//#define WSAGETSELECTERROR(lParam) HIWORD(lParam)
//#define WSAGETSELECTEVENT(lParam) LOWORD(lParam) // 由于从 ClientSocket 中连接成功的套接字全部用 FD_CONNECT
// 参数调用了 WSAAsyncSelect 函数. 因此, 对这些套接字的任何 "非重叠" 的发送或接收调用
// 都是 "非阻塞" 调用, 如果不显式用 WSAAsyncSelect 重新设置这些套接字的
// "非阻塞" 调用机制 (机制包括: 1. 想要接收的网络事件; 2. 接收事件的窗口;
// 3. 以什么消息值发送), 将会永远接收不到网络事件. 因为 ClientSocket 没有
// 注册其他事件除了 FD_CONNECT.
//
// 解决方案:
//
// 1. 使用重叠 IO 机制. MSDN 明确指出, 不管套接字是否处于阻塞模式
// 重叠 IO 都将正常工作
//
// 2. 使用 WSAAsyncSelect 重新设置: 1. 想要接收的网络事件; 2. 接收事件的窗口
// 3. 以什么消息值来发送
//
// 3. 使用 WSAEventSelect 重新设置网络事件的通知方式
// (当发生网络事件时, 置一个关联的 WIN32 事件对象为通信状态, 用 Wait 系列方法等待成功后
// 可用 WSAEnumNetevents 获取引发的网络事件信息 _ASSERTE( FD_CONNECT == WSAGETSELECTEVENT(msg.lParam) ); error = WSAGETSELECTERROR(msg.lParam); rs = pendingRequest[(int) (msg.message - MIN_SOCKET_INDEX)];
_ASSERTE(rs != NULL);
if( rs == NULL )
continue; _ASSERTE( rs->index == (int)(msg.message - MIN_SOCKET_INDEX) );
//_ASSERTE( rs->sock == (SOCKET)msg.wParam ); if( 0 == error )
{
// 成功连接 !
if( this->pCompletion != NULL )
{
pCompletion->ConnectionCompletionSucceeded(
rs->sock, rs->index, rs->address, rs->port, rs->data
);
}
else
{
closesocket( rs->sock );
} putIndex( rs->index );
pendingRequest[rs->index] = NULL;
delete rs;
}
else
{
// 连接失败了
if( this->pCompletion != NULL )
{
pCompletion->ConnectionCompletionFailed(
rs->index, error, rs->address, rs->port, 0
);
} pendingRequest[rs->index] = NULL;
sockCache.push_back( rs );
} } // 添加连接请求, 客户要求进行 TCP 连接
else if( WM_ADD_CONNECT_NOTIFY == msg.message )
{
rs = (ConnectRequest*)msg.wParam; addr.sin_addr.S_un.S_addr = rs->address;
addr.sin_port = rs->port; //_RPT1( _CRT_WARN, "%d", sockCache.size() );
if( sockCache.size() > 0 )
{
rs2 = sockCache.back();
sockCache.pop_back(); putIndex( rs2->index );
rs->sock = rs2->sock; }
else
{
rs->sock = socket( AF_INET, SOCK_STREAM, 0 );
if( INVALID_SOCKET == rs->sock )
{
error = WSAGetLastError();
if( this->pCompletion != NULL )
pCompletion->ConnectionCompletionFailed(
rs->index, error, rs->address, rs->port, rs->data); putIndex( rs->index );
delete rs;
continue;
}
} error = WSAAsyncSelect(
rs->sock, hwnd, rs->index + MIN_SOCKET_INDEX, FD_CONNECT ); _ASSERTE( 0 == error ); error = connect( rs->sock, (sockaddr*)(&addr), sizeof(sockaddr_in) );
if( SOCKET_ERROR == error )
{
error = WSAGetLastError();
if( error != WSAEWOULDBLOCK )
{
if( this->pCompletion != NULL )
pCompletion->ConnectionCompletionFailed(
rs->index, error, rs->address, (unsigned short)(rs->port), rs->data ); sockCache.push_back( rs );
continue;
}
else
{
// _ASSERTE( FALSE );
}
} _ASSERTE( pendingRequest[rs->index] == NULL );
pendingRequest[rs->index] = rs; continue;
}
else if( WM_CANCEL_CONNECT_REQUEST == msg.message )
{ // 取消连接请求 _ASSERTE( FALSE );
rs = pendingRequest[ msg.wParam ]; _ASSERTE( rs->index == msg.wParam ); if( rs != NULL )
{
if( this->pCompletion != NULL )
pCompletion->ConnectionRequestCancelResult(
TRUE, rs->index, rs->address, rs->port, rs->data ); closesocket( rs->sock );
putIndex( rs->index );
delete rs;
pendingRequest[msg.wParam] = NULL;
}
else
{
if( this->pCompletion != NULL )
pCompletion->ConnectionRequestCancelResult(
FALSE, (int)msg.wParam, 0, 0, 0 ); }
}
else if( WM_EXIT_NOTIFY == msg.message )
{
// 线程退出通知. 强制销毁窗口, 强制删除所有的未决连接, 及缓存的套接字
// 系统向窗口发出的任何网络事件被忽略不睬 _ASSERTE( !bInitialized ); int i = 0;
int c = (int)pendingRequest.size(); DestroyWindow( hwnd );
for ( ; i<c; i++ )
{
rs = pendingRequest[i];
if( rs != NULL )
{
closesocket (rs->sock);
delete rs;
}
} while (sockCache.size() != 0)
{
rs = sockCache.back();
sockCache.pop_back();
::closesocket( rs->sock );
delete rs;
} pendingRequest.clear();
sockCache.clear();
availIndex.clear(); // 返回, 意味着结束当前线程 !
return 0;
}
else
{
DispatchMessage( &msg );
}
continue;
}
}
unsigned int __stdcall ClientSocket::BeginWork( void * p )
{
ClientSocket* pthis = (ClientSocket*)p; pthis->window = CreateWindow(
ClientSocket::CLIENT_SOCKET_WINDOW_CLASS_NAME,
" ",
NULL,
0,0,0,0,
NULL,
NULL,
NULL,
pthis
); _ASSERTE( pthis->window != NULL );
_ASSERTE( pthis->event != NULL ); SetEvent( pthis->event ); return pthis->MessageLoop();
}
ClientSocket::ClientSocket( BOOL bInit )
: thread(NULL), window(NULL), threadID(0), bInitialized(FALSE)
{
if( !bRegistered )
{
WNDCLASS wc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 4;
wc.hbrBackground= NULL;
wc.hCursor = NULL;
wc.hIcon = NULL;
wc.hInstance = GetModuleHandle(NULL);
wc.lpfnWndProc = rpt::ClientSocket::WindowProc;
wc.lpszClassName= rpt::ClientSocket::CLIENT_SOCKET_WINDOW_CLASS_NAME;
wc.lpszMenuName = NULL;
wc.style = 0; RegisterClass(&wc); bRegistered = TRUE;
} if( bInit )
initialize();
}
raw socket如何调用?
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include "mstcpip.h"
#pragma comment(lib,"ws2_32")#define DEFAULT_DEST_PORT 5
#define DEST_HOST "www.hrbust.edu.cn"
#define SEQ 0x28376839typedef struct _iphdr
{
unsigned char h_lenver; //4位首部长度+4位IP版本号
unsigned char tos; //8位服务类型TOS
unsigned short total_len; //16位总长度(字节)
unsigned short ident; //16位标识
unsigned short frag_and_flags; //3位标志位
unsigned char ttl; //8位生存时间 TTL
unsigned char proto; //8位协议 (TCP, UDP 或其他)
unsigned short checksum; //16位IP首部校验和
unsigned int sourceIP; //32位源IP地址
unsigned int destIP; //32位目的IP地址
}IP_HEADER;typedef struct _tcphdr //定义TCP首部
{
USHORT th_sport; //16位源端口
USHORT th_dport; //16位目的端口
unsigned int th_seq; //32位序列号
unsigned int th_ack; //32位确认号
unsigned char th_lenres; //4位首部长度/6位保留字
unsigned char th_flag; //6位标志位
USHORT th_win; //16位窗口大小
USHORT th_sum; //16位校验和
USHORT th_urp; //16位紧急数据偏移量
}TCP_HEADER; struct //定义TCP伪首部
{
unsigned long saddr; //源地址
unsigned long daddr; //目的地址
char mbz;
char ptcl; //协议类型
unsigned short tcpl; //TCP长度
}psd_header;SOCKET sockRaw = INVALID_SOCKET,
sockListen = INVALID_SOCKET;
struct sockaddr_in dest;//SOCK错误处理程序
void CheckSockError(int iErrorCode, char *pErrorMsg)
{
if(iErrorCode==SOCKET_ERROR)
{
printf("%s Error:%d\n", pErrorMsg, GetLastError());
closesocket(sockRaw);
ExitProcess(-1);
}}//计算检验和
USHORT checksum(USHORT *buffer, int size)
{
unsigned long cksum=0; while (size > 1)
{
cksum += *buffer++;
size -= sizeof(USHORT);
}
if (size)
{
cksum += *(UCHAR*)buffer;
}
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
return (USHORT)(~cksum);
}//IP解包程序
bool DecodeIPHeader(char *buf, int bytes)
{
IP_HEADER *iphdr;
TCP_HEADER *tcphdr;
unsigned short iphdrlen; iphdr = (IP_HEADER *)buf;
iphdrlen = sizeof(unsigned long) * (iphdr->h_lenver & 0xf);
tcphdr = (TCP_HEADER*)(buf + iphdrlen);//是否来自目标IP
if(iphdr->sourceIP != dest.sin_addr.s_addr) return false;//序列号是否正确
if((ntohl(tcphdr->th_ack) != (SEQ+1)) && (ntohl(tcphdr->th_ack) != SEQ)) return false;//RST/ACK - 无服务
if(tcphdr->th_flag == 20)
{
printf(".\n");
return true;
}//SYN/ACK - 扫描到一个端口
if(tcphdr ->th_flag == 18)
{
printf("%d\n",ntohs(tcphdr->th_sport));
return true;
} return true;
}//主函数
int main(int argc,char **argv)
{
int iErrorCode;
int datasize;
struct hostent *hp;
IP_HEADER ip_header;
TCP_HEADER tcp_header;
char SendBuf[128]={0};
char RecvBuf[65535]={0};//初始化SOCKET
WSADATA wsaData;
iErrorCode = WSAStartup(MAKEWORD(2,2),&wsaData);
CheckSockError(iErrorCode, "WSAStartup()");
sockRaw = socket(AF_INET , SOCK_RAW , IPPROTO_IP);
CheckSockError(sockRaw, "socket()");
sockListen = socket(AF_INET , SOCK_RAW , IPPROTO_IP);
CheckSockError(sockListen, "socket");//设置IP头操作选项
BOOL bOpt = true;
iErrorCode = setsockopt(sockRaw,IPPROTO_IP,IP_HDRINCL,(char *)&bOpt,sizeof(bOpt));
CheckSockError(iErrorCode, "setsockopt()"); //获得本地IP
SOCKADDR_IN sa;
unsigned char LocalName[256];iErrorCode = gethostname((char*)LocalName,sizeof(LocalName)-1);
CheckSockError(iErrorCode, "gethostname()");
if((hp = gethostbyname((char*)LocalName)) == NULL)
{
CheckSockError(SOCKET_ERROR, "gethostbyname()");
}
memcpy(&sa.sin_addr.S_un.S_addr,hp->h_addr_list[0],hp->h_length);
sa.sin_family = AF_INET;
sa.sin_port = htons(7000);
iErrorCode = bind(sockListen, (PSOCKADDR)&sa, sizeof(sa));
CheckSockError(iErrorCode, "bind");//设置SOCK_RAW为SIO_RCVALL,以便接收所有的IP包
DWORD dwBufferLen[10] ;
DWORD dwBufferInLen = 1 ;
DWORD dwBytesReturned = 0 ;
iErrorCode=WSAIoctl(sockListen, SIO_RCVALL,&dwBufferInLen, sizeof(dwBufferInLen),
&dwBufferLen, sizeof(dwBufferLen),&dwBytesReturned , NULL , NULL );
CheckSockError(iErrorCode, "Ioctl");//获得目标主机IP
memset(&dest,0,sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_port = htons(DEFAULT_DEST_PORT);
if((dest.sin_addr.s_addr = inet_addr(DEST_HOST)) == INADDR_NONE)
{
if((hp = gethostbyname(DEST_HOST)) != NULL)
{
memcpy(&(dest.sin_addr),hp->h_addr_list[0],hp->h_length);
dest.sin_family = hp->h_addrtype;
printf("dest.sin_addr = %s\n",inet_ntoa(dest.sin_addr));
}
else
{
CheckSockError(SOCKET_ERROR, "gethostbyname()");
}
}//填充IP首部
ip_header.h_lenver=(4<<4 | sizeof(ip_header)/sizeof(unsigned long));
//高四位IP版本号,低四位首部长度
ip_header.total_len=htons(sizeof(IP_HEADER)+sizeof(TCP_HEADER)); //16位总长度(字节)
ip_header.ident=1; //16位标识
ip_header.frag_and_flags=0; //3位标志位
ip_header.ttl=128; //8位生存时间TTL
ip_header.proto=IPPROTO_TCP; //8位协议(TCP,UDP…)
ip_header.checksum=0; //16位IP首部校验和
ip_header.sourceIP=sa.sin_addr.s_addr; //32位源IP地址
ip_header.destIP=dest.sin_addr.s_addr; //32位目的IP地址//填充TCP首部
tcp_header.th_sport=htons(7000); //源端口号
tcp_header.th_dport=htons(DEFAULT_DEST_PORT); //目的端口号
tcp_header.th_seq=htonl(SEQ); //SYN序列号
tcp_header.th_ack=0; //ACK序列号置为0
tcp_header.th_lenres=(sizeof(TCP_HEADER)/4<<4|0); //TCP长度和保留位
tcp_header.th_flag=2; //SYN 标志
tcp_header.th_win=htons(16384); //窗口大小
tcp_header.th_urp=0; //偏移
tcp_header.th_sum=0; //校验和//填充TCP伪首部(用于计算校验和,并不真正发送)
psd_header.saddr=ip_header.sourceIP;
psd_header.daddr=ip_header.destIP;
psd_header.mbz=0;
psd_header.ptcl=IPPROTO_TCP;
psd_header.tcpl=htons(sizeof(tcp_header));//计算TCP校验和,计算校验和时需要包括TCP pseudo header
memcpy(SendBuf,&psd_header,sizeof(psd_header));
memcpy(SendBuf+sizeof(psd_header),&tcp_header,sizeof(tcp_header));
tcp_header.th_sum=checksum((USHORT *)SendBuf,sizeof(psd_header)+sizeof(tcp_header));//计算IP校验和
memcpy(SendBuf,&ip_header,sizeof(ip_header));
memcpy(SendBuf+sizeof(ip_header),&tcp_header,sizeof(tcp_header));
memset(SendBuf+sizeof(ip_header)+sizeof(tcp_header),0,4);
datasize=sizeof(ip_header)+sizeof(tcp_header);
ip_header.checksum=checksum((USHORT *)SendBuf,datasize);//填充发送缓冲区
memcpy(SendBuf,&ip_header,sizeof(ip_header));//发送TCP报文
iErrorCode=sendto(sockRaw,SendBuf,datasize,0,(struct sockaddr*) &dest,
sizeof(dest));
CheckSockError(iErrorCode, "sendto()");//接收数据
DWORD timeout = 2000;
DWORD start = GetTickCount();
while(true)
{
//计时,2s超时
if((GetTickCount() - start) >= timeout) break;memset(RecvBuf, 0, sizeof(RecvBuf));
iErrorCode = recv(sockListen, RecvBuf, sizeof(RecvBuf), 0);
CheckSockError(iErrorCode, "recv");if(DecodeIPHeader(RecvBuf,iErrorCode)) break;
}//退出前清理
if(sockRaw != INVALID_SOCKET) closesocket(sockRaw);
WSACleanup();
return 0;
}
好象是端口重用建议你用多线程
然后用select来进行超时管理
超时了就shutdown,然后再closesocket
recv可以用shutdown没错,但connect()也可以吗?