⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 socketex.cpp

📁 C++ patterns设计模式
💻 CPP
📖 第 1 页 / 共 2 页
字号:
////////////////////////////////////////////////////////////////////////////////
// 
////////////////////////////////////////////////////////////////////////////////
// Author      : 黎达文                                                        
// Description : 
//
// Version     : 
//
// Standard include files : 
//
// Start Date  : 2003年8月16日
//
// Change Log  : 2003年8月16日 by 黎达文 -- Created
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "socketex.h"
#include "patterns/util/util.h"

#include <sys/timeb.h>
#include <time.h>

#if defined( WIN32 )
#   define  timeb   _timeb
#   define  ftime   _ftime
#endif

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define M_Int2Str(x)		#x
#define M_SymToStr(x)		M_Int2Str(x)
#define remind(desc)		message(__FILE__"("M_SymToStr(__LINE__)") :"#desc)
#define M_POS   			__FILE__ "(" M_SymToStr( __LINE__ ) "):"


namespace acl
{
	//////////////////////////////////////////////////////////////////////////////
	BufferedSocket::BufferedSocket()
	{
        m_cur = 0;
        m_cnt = 0;
        stk::bzero(m_buf, 0);
	}

    //////////////////////////////////////////////////////////////////////////////
    // Function Name       : ctor
    //////////////////////////////////////////////////////////////////////////////
    AbstractSocket::AbstractSocket(SOCKET_TYPE type)
        : m_type(type)
        , m_socket(INVALID_SOCKET)
    {
    }

    //////////////////////////////////////////////////////////////////////////////
    // Function Name       : type conversion operator
    // Return Value        : SOCKET
    //////////////////////////////////////////////////////////////////////////////
    AbstractSocket::operator SOCKET() const
    {
        return m_socket;
    }

    //////////////////////////////////////////////////////////////////////////////
    // Function Name       : attach
    // Description         : attach an existing SOCKET to current object
    // Input Parameters    : the SOCKET
    //////////////////////////////////////////////////////////////////////////////
    void AbstractSocket::attach(SOCKET sock)
    {
        close();
        m_socket = sock;        
    }

    //////////////////////////////////////////////////////////////////////////////
    // Function Name       : detach
    // Description         : return the SOCKE to the user, current object will not own the SOCKET
    // Return Value        : the SOCKET
    //////////////////////////////////////////////////////////////////////////////
    SOCKET AbstractSocket::detach()
    {
        assert(m_socket != INVALID_SOCKET);
        SOCKET tmp = m_socket;
        m_socket = INVALID_SOCKET;
        return tmp;
    }

    //////////////////////////////////////////////////////////////////////////////
    // Function Name       : create
    // Description         : create the SOCKET 
    // Return Value        : success/fail
    //////////////////////////////////////////////////////////////////////////////
    bool AbstractSocket::create()
    {
		assert(m_socket == INVALID_SOCKET);

        if(m_type == TCP_SOCKET)
            m_socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        else if(m_type == UDP_SOCKET)
            m_socket = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
        else
            m_socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_IP);

        return m_socket != INVALID_SOCKET;
    }

    //////////////////////////////////////////////////////////////////////////////
    // Function Name       : close
    // Description         : close the socket if it had opened, I will not try to shutdown the socket!
    //////////////////////////////////////////////////////////////////////////////
    void AbstractSocket::close()
    {
        if(m_socket != INVALID_SOCKET)
        {
			::closesocket(m_socket);
            m_socket = INVALID_SOCKET;
        }
    }

    //////////////////////////////////////////////////////////////////////////////
    // Function Name       : send
    // Description         : send buffer just like the SOCKET API
    // Input Parameters    : outbuf -- buffer will be send
    //                       want   -- how much byte you want to be send
    //                       as you known, SOCKET API may not send all data you want!
    //                       if you want to make sure send all data, use sendAll method
    // Return Value        : If no error occurs, recv returns the number of bytes received. 
    //                       If the connection has been gracefully closed, the return value is zero. 
    ///                      Otherwise, a value of SOCKET_ERROR is returned
    //////////////////////////////////////////////////////////////////////////////
    int AbstractSocket::send(const char *outbuf, int want) const
    {
        assert(m_socket!=INVALID_SOCKET);
        assert(outbuf);
        assert(want>0);

        return ::send(m_socket, outbuf, want, 0);
    }

    //////////////////////////////////////////////////////////////////////////////
    // Function Name       : recv
    // Description         : recv data just like the SOCKET API
    // Input Parameters    : inbuf -- where data will be store
    //                     : size  -- size of inbuf
    // Return Value        : If no error occurs, recv returns the number of bytes received. 
    //                       If the connection has been gracefully closed, the return value is zero. 
    ///                      Otherwise, a value of SOCKET_ERROR is returned
    //////////////////////////////////////////////////////////////////////////////
    int AbstractSocket::recv(char *inbuf, int size) const
    {
        assert(m_socket!=INVALID_SOCKET);
        assert(inbuf);
        assert(size>0);

        return ::recv(m_socket, inbuf, size, 0);
    }

    //////////////////////////////////////////////////////////////////////////////
    // Function Name       : sendAll
    // Description         : try to send all the outbuf
    // Input Parameters    : outbuf -- the data which want to be send
    //                       want   -- how many bytes you wan to send
    // Return Value        : If no error occurs, recv returns the number of bytes send. 
    //                       If the connection has been gracefully closed, the return value is zero. 
    ///                      Otherwise, a value of SOCKET_ERROR is returned
    //////////////////////////////////////////////////////////////////////////////
    int AbstractSocket::sendAll(const char *outbuf, int want) const
    {
        assert(m_socket!=INVALID_SOCKET);
        assert(outbuf);
        assert(want>0);

        int left;
        int idx;
        int ret;
        left = want;
        idx  = 0;
        while(left > 0)
        {
            ret = ::send(m_socket, &outbuf[idx], left, 0);
            // send error, or has been close by peer
            if(ret == 0 || ret == SOCKET_ERROR)
                break;
            left -= ret;
            idx  += ret;
        }
        // left == 0 means we do the job successfully
        return left == 0 ? idx : ret;
    }

    //////////////////////////////////////////////////////////////////////////////
    // Function Name       : recvAll
    // Description         : try to recv all data we want
    // Input Parameters    : inbuf -- where to store data
    //                       want  -- how much data we want
    // Return Value        : If no error occurs, recv returns the number of bytes received. 
    //                       If the connection has been gracefully closed, the return value is zero. 
    ///                      Otherwise, a value of SOCKET_ERROR is returned
    //////////////////////////////////////////////////////////////////////////////
    int AbstractSocket::recvAll(char *inbuf, int want) const
    {
        assert(m_socket!=INVALID_SOCKET);
        assert(inbuf);
        assert(want>0);

        int ret;
        int read = 0;
        while(read < want)
        {
            ret = recv(&inbuf[read], want-read);
            // send error, or has been close by peer
            if(ret == 0 || ret == SOCKET_ERROR)
                break;
            read += ret;
        }
        // read == want means we do the job successfully
        return read == want ? read : ret;
    }

	static unsigned long timediff(timeb &first, timeb &second)
	{
		unsigned long elap = (second.time - first.time) * 1000;
		if ( second.millitm > first.millitm )
			elap += second.millitm - first.millitm;
		else
			elap -= first.millitm - second.millitm;
		return elap;
	}
    //////////////////////////////////////////////////////////////////////////////
    // Function Name       : recvAsyn
    // Description         : recv in asynchronous way, with timeout
    // Input Parameters    : inbuf -- where to store data
    //                       want  -- how much data we want
    //                       timeout -- timeout(unit: s)
    // Return Value        : If no error occurs, recv returns the number of bytes received. 
    //                       If the connection has been gracefully closed, the return value is zero. 
    //                       Otherwise, a value of SOCKET_ERROR is returned
    //                       Timeout will look as SOCKET_ERROR
    //////////////////////////////////////////////////////////////////////////////
    int AbstractSocket::recvAsyn(char *inbuf, int want, DWORD timeout) const
    {
        assert(m_socket!=INVALID_SOCKET);
        assert(inbuf);
        assert(want>0);

        int ret;
        int read;

        timeb first_tick, second_tick;

        timeval tv = {1, 0};	// default is check timeout per 1 second
        timeval *ptv = &tv;
        if(timeout == INFINITE)	
            ptv = NULL;         // NULL indicate select recvReady wait for ever

        ftime( &first_tick );
        read = 0;
        while(read < want)
        {
            if(recvReady(ptv))
            {
                ret = recv(inbuf+read, want-read);
                if(ret == 0 || ret == SOCKET_ERROR)
                    break;
                // if no error, ret is the real size we had recv
                read += ret;
            } 
            ftime( &second_tick ) ;          
            // check for timeout
            unsigned long elap = timediff(second_tick, first_tick);
            if(elap > timeout)
            {
                ret = SOCKET_ERROR;
                break;
            }
        }
        // read == want means we do the job successfully
        return read == want ? read : ret;
    }


	//////////////////////////////////////////////////////////////////////////////
	// Function Name       : getline
	// Description         : get a line from socket
	//						 method will try to read a block data from socket
	//					     and save it into BufferedSocket. and then find a line
	//					     and return. That method will avoid call recv function one by one
	// Input Parameters    : bs : must pass this object in a serial read action
	// Return Value        : like the ::recv
	//////////////////////////////////////////////////////////////////////////////
	int AbstractSocket::getline(BufferedSocket &bs, 
                                std::string &line, 
                                const char *eof) const
	{	
        const char *eofBeg = eof;
        const char *eofEnd = eof + strlen(eof);
        char *pos;
        char *end;
        char *beg;
        while(true)
        {
            // check whether we have any buffer
            if(bs.m_cnt <= 0)
            {
                // recv a new buffer
                bs.m_cnt = this->recv(bs.m_buf, BufferedSocket::BUF_SIZE);
                // if socket error, return it directly
                if(bs.m_cnt <= 0)
                    return bs.m_cnt;

                // set the string
                bs.m_cur = bs.m_buf;
            }
            // search the "eof" position
            end = bs.m_cur+bs.m_cnt;
            beg = bs.m_cur;
            pos = std::search(beg, end, 
                              eofBeg, eofEnd);
            line.append(beg, pos);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -