我想编一个网络扫描器,使用了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不至于太多。
真搞不懂那些商业扫描器是怎么做的?

解决方案 »

  1.   

    WinSock 2 有个特性,可以让你绑定 TIME_WAIT 状态的端口,用一个标志就可以搞定,我给你查查
      

  2.   

    setsockopt(Server,SOL_SOCKET,SO_REUSEADDR,(LPCSTR)&val,4);就是那个 SO_REUSEADDR
      

  3.   

    ...........
    试试先shutdown
    另外如果一个socket没有连接成功,可以继续使用的
      

  4.   

    楼主作扫描应该使用异步方式,而不应该用同步方式阿,close是能关闭联接的
      

  5.   

    用shutdown函数
    异步方式是不是要有一个窗口支持啊?
      

  6.   

    ::::setsockopt(Server,SOL_SOCKET,SO_REUSEADDR,(LPCSTR)&val,4);  
    ::::就是那个  SO_REUSEADDR 
    有没有完整一点的代码?
      

  7.   

    tcp连接关闭后有可能会延时关闭端口,一般是2秒左右
    =fly by=
      

  8.   

    这是使用阻塞方式实现连接超时的代码:(是LocalVar(分乃身外之物,即使我回答对了,也别给分) 的代码)看看对你是否有帮助?再加上多线程你的扫描器有救了!
    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;
    }
      

  9.   

    非常感谢 himming(海明码) 我还有个疑问
    setsockopt(Server,SOL_SOCKET,SO_REUSEADDR,(LPCSTR)&val,4);
    就是那个SO_REUSEADDR
    如何使用?用在什么地方?
      

  10.   

    如果用 WINDOWS 的专用模型会更好,不用多少线程,两个就够了。我贴我以前写的类出来让大家一起分享,看看,评评。呵呵,献丑了:)另外,由于这个类是在一个我自己写的类库里面的,还用上了别的一些类,在此与客户相关的类一并贴出class IConnectionCompletion
    {
    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;
    };
      

  11.   

    // 这里贴的是一个内存池,它实现以指定大小为分配单位的内存池
    // 最后还有一些宏,用于给一个类进行池方式的分配与释放
    // 另外还有一个实现多线程同步的内存池,由于这里不需要, 我就不贴了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 );
      

  12.   

    直接用raw socket发SYN的IP包,这样多快
      

  13.   

    //  模板参数类型 T 的要求是, 它必须是 rpt::ClientSocket::ConnectRequest 类, 或其子类
    //  但凡继承自 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 );
    }
      

  14.   

    unsigned int ClientSocket::MessageLoop()
    {
        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;
        }
    }
      

  15.   


    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();
    }
      

  16.   

    To:cnss(K) 
    raw socket如何调用?
      

  17.   

    raw socket 只能在2k下使用,给你一个断口扫描的:
    #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;
      

  18.   

    y97523szb () :要是同步(阻塞)方式的connect(),确实无法用close()关闭,其实不止是connect(),Recv()也会停在那里的。丢丢:你说的那个标志设置以后能实现一下子就关掉处于阻塞状态下的SOCKET吗?
      

  19.   

    SO_REUSEADDR 
    好象是端口重用建议你用多线程
    然后用select来进行超时管理
    超时了就shutdown,然后再closesocket
      

  20.   

    snsins:
    recv可以用shutdown没错,但connect()也可以吗?