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

📄 sock.cpp

📁 基于Perl的HTTP协议GUI测试程序
💻 CPP
字号:
#include "sock.h"
#include <stdio.h>
#include <stdarg.h>

void tracef(const char* str, ...)
{
    va_list args;
    va_start(args, str);
    //vprintf(str, args);
    va_end(args);
};

#ifdef WIN32

#pragma comment( lib, "wsock32" )

typedef int socklen_t;

class dummy
{
public:
    dummy();
    ~dummy();
};

static dummy theDummy;

dummy::dummy()
{
    tracef("WSAStartup\n");
    WORD wVersionRequested;
    WSADATA wsaData;
    int err; 

    wVersionRequested = MAKEWORD( 1, 1 ); 
    err = WSAStartup( wVersionRequested, &wsaData );
    if ( err != 0 )
    {
        /* Tell the user that we could not find a usable */
        /* WinSock DLL.                                  */
        return;
    } 

    /* Confirm that the WinSock DLL supports 1.1.*/
    /* Note that if the DLL supports versions greater    */
    /* than 1.1 in addition to 1.1, it will still return */
    /* 1.1 in wVersion since that is the version we      */
    /* requested.                                        */ 
    if ( LOBYTE( wsaData.wVersion ) != 1 ||
        HIBYTE( wsaData.wVersion ) != 1 )
    {
        /* Tell the user that we could not find a usable */
        /* WinSock DLL.                                  */
        WSACleanup( );
        return;
    }

    /* The WinSock DLL is acceptable. Proceed. */
    return;
}

dummy::~dummy()
{
    tracef("WSACleanup\n");
    WSACleanup();
}

int getSocketError()
{
    return WSAGetLastError();
}

int setNonBlocking(SOCKET sock)
{
    unsigned long arg = 1;
    return ioctlsocket(sock, FIONBIO, &arg);
}

#else // WIN32

#include <sys/ioctl.h>
#include <netdb.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>

#define INVALID_SOCKET (-1)

typedef struct hostent HOSTENT;
typedef struct sockaddr SOCKADDR;

int getSocketError()
{
    return errno;
}

int closesocket(SOCKET s)
{
    return close(s);
}

int setNonBlocking(SOCKET sock)
{
    int status = 1;
    if((status = fcntl(sock, F_GETFL, 0)) != -1)
    {
	status |= O_NONBLOCK;
	status = fcntl(sock, F_SETFL, status);
    }
    return status;
}

#endif // WIN32


int get_address(const char* host, int port, SOCKADDR_IN* pAdr)
{
    // first try name as ip addr
    pAdr->sin_addr.s_addr = inet_addr(host);
    if(pAdr->sin_addr.s_addr == INADDR_NONE)
    {
        // now try name lookup
        HOSTENT* phe;
        phe = gethostbyname(host);
        if(phe == NULL)
            return -1;

        memcpy(&pAdr->sin_addr.s_addr, phe->h_addr, sizeof(pAdr->sin_addr.s_addr));
    }

    pAdr->sin_family = AF_INET;
    pAdr->sin_port = htons(port);
    memset(pAdr->sin_zero, 0, sizeof(pAdr->sin_zero));

    return 0;
}

/* ----------------------------------------------
 * CTcpSock implementation
 * ----------------------------------------------
 */

CTcpSock::CTcpSock(void)
{
    m_state = start;
    m_context = NULL;
    m_cbConnectOk = NULL;
    m_cbSendOk = NULL;
    m_cbReadLineOk = NULL;
    m_cbRecvBufOk = NULL;
    m_intStatus = noEvent;
    m_eof = 0;
}

CTcpSock::~CTcpSock(void)
{
    close();
}

int CTcpSock::create(void)
{
    tracef("creating socket ... ");
    m_sock = ::socket(AF_INET, SOCK_STREAM, 0);
    if(m_sock != INVALID_SOCKET)
    {
	setNonBlocking(m_sock);
        // TODO: check for failure to set nonblocking socket
        m_state = created;
        tracef("OK, fd=0x%08x\n", m_sock);
        return 0;
    }
    else
    {
        tracef("FAILED\n");
        return -1;
    }
}

int CTcpSock::close(void)
{
    int res = 0;
    if(m_state != closed &&
        m_state != start)
    {
        tracef("closing socket ... ");
        res = ::closesocket(m_sock);
        if(res == 0)
        {
            m_state = closed;
            tracef("OK\n");
        }
        else
        {
            tracef("FAILED [%d]\n", getSocketError());
        }
    }
    return res;
}

int CTcpSock::connect(SOCKADDR_IN* name)
{
    tracef("connecting to %s\n", inet_ntoa(name->sin_addr));
    int res = 0;
    if(m_state == created)
    {
        res = ::connect(m_sock, (SOCKADDR*) name, sizeof(SOCKADDR_IN));
        m_state = connecting;
    }
    return res;
}

int CTcpSock::send(const char* buf, int len)
{
    tracef("sending %d bytes\n", len);
    tracef(" %s\n", buf);
    int res = 0;
    if(m_state == ready)
    {
        res = ::send(m_sock, buf, len, 0);
        m_sent = res;
        m_wlen = len;
        m_wbuf = buf;
	if(res < 0)
	{
	    tracef("send error: %d\n", getSocketError());
	    m_sent = 0;
	}
        if(res < len)
        {
            m_state = sending;
        }
        else
        {
            tracef("send DONE OK\n");
            m_state = ready;
            m_intStatus = sendOk;
        }
    }
    return res;
}

int CTcpSock::sendString(const char* str)
{
    return send(str, strlen(str));
}

void CTcpSock::recvBufLoop(void)
{
    int res = 0;
    m_state = recievingBuf;
    while(1)
    {
        m_eof = 0;
        int done = 0;
        res = ::recv(m_sock, &m_rbuf[m_read], m_rlen - m_read, 0);
        if(res < 0)
            break;
        if(res == 0)
        {
            m_eof = 1;
            done = 1;
        }
        m_read += res;
        if(m_read == m_rlen)
            done = 1;
        if(done)
        {
            m_state = ready;
            m_intStatus = recvBufOk;
            break;
        }
    }
}

int CTcpSock::recvBuf(char* buf, int len)
{
    tracef("Receiving buffer ...\n");
    int res = 0;
    if(m_state == ready)
    {
        m_read = 0;
        m_rlen = len;
        m_rbuf = buf;
        recvBufLoop();
    }
    return res;
}

void CTcpSock::readLineLoop(void)
{
    int res = 0;
    m_state = readingLine;
    while(1)
    {
        m_eof = 0;
        int done = 0;
        res = ::recv(m_sock, &m_rbuf[m_read], 1, 0);
        if(res < 0)
            break;
        if(res == 0)
        {
            m_eof = 1;
            done = 1;
        }
        if(m_rbuf[m_read] == 10)
        {
            done = 1;
        }
        else
        {
            if(m_rbuf[m_read] != 13)
                m_read += res;
        }
        if(m_read >= m_rlen - 1)
            done = 1;
        if(done)
        {
            m_rbuf[m_read] = 0;
            m_state = ready;
            m_intStatus = readLineOk;
            break;
        }
    }
}

int CTcpSock::readLine(char* buf, int max_len)
{
    tracef("reading line ... \n");
    int res = 0;
    if(m_state == ready)
    {
        m_read = 0;
        m_rlen = max_len;
        m_rbuf = buf;
        readLineLoop();
    }

    return res;
}

int CTcpSock::setFdSets(fd_set* rfds, fd_set* wfds, fd_set* efds)
{
    FD_CLR(m_sock, rfds);
    FD_CLR(m_sock, wfds);
    FD_SET(m_sock, efds);

    switch(m_state)
    {
    case connecting:
        FD_SET(m_sock, wfds);
        break;
    case sending:
        FD_SET(m_sock, wfds);
        break;
    case readingLine:
        FD_SET(m_sock, rfds);
        break;
    case recievingBuf:
        FD_SET(m_sock, rfds);
        break;
    }
    return 0;
}

int CTcpSock::checkFdSets(fd_set* rfds, fd_set* wfds, fd_set* efds)
{
    int event = 0;
    if(FD_ISSET(m_sock, rfds)) event |= read;
    if(FD_ISSET(m_sock, wfds)) event |= write;
    if(FD_ISSET(m_sock, efds)) event |= except;
    if(event != 0)
        processEvent(event);
    // process internal events
    while(m_intStatus != noEvent)
    {
        int theEvent = m_intStatus;
        m_intStatus = noEvent;
        switch(theEvent)
        {
        case connectOk:
            if(m_cbConnectOk)
                (*m_cbConnectOk)(this);
            break;
        case sendOk:
            if(m_cbSendOk)
                (*m_cbSendOk)(this);
            break;
        case readLineOk:
            if(m_cbReadLineOk)
                (*m_cbReadLineOk)(this);
            break;
        case recvBufOk:
            if(m_cbRecvBufOk)
                (*m_cbRecvBufOk)(this);
            break;
        }

        if(m_intStatus == deleteEvent)
        {
            delete this;
            return 0;
        }
    }
    return 0;
};
    
int CTcpSock::processEvent(int event)
{
    switch(m_state)
    {
    case connecting:
        if(event & except)
        {
            tracef("connect FAILED\n");
            m_state = created;
            // TODO: make callback
            break;
        }
        if(event & write)
        {
	    int res;
	    int len = sizeof(res);
	    getsockopt(m_sock, SOL_SOCKET, SO_ERROR, (char *) &res, (socklen_t*) &len);
	    if(res == 0)
	    {
		tracef("connect OK\n");
		m_state = ready;
		m_intStatus = connectOk;
	    }
	    else
	    {
		tracef("connect FAILED\n");
		m_state = created;
		// TODO: make callback
	    }
        }
        break;
    case sending:
        if(event & except)
        {
            tracef("send FAILED\n");
            m_state = ready;
            // TODO: make callback
            break;
        }
        if(event & write)
        {
            tracef("send ... \n");
            if(m_sent < m_wlen)
            {
                int res;
                res = ::send(m_sock, &m_wbuf[m_sent], m_wlen - m_sent, 0);
                if(res >= 0)
                {
                    m_sent += res;
                }
                else
                {
                    // TODO: handle send error
                }
                if(m_sent == m_wlen)
                {
                    tracef("send DONE OK\n");
                    m_state = ready;
                    m_intStatus = sendOk;
                }
            }
        }
        break;
    case readingLine:
        if(event & except)
        {
            tracef("read FAILED");
            m_state = ready;
            // TODO: make callback
            break;
        }
        if(event & read)
        {
            readLineLoop();
        }
        break;
    case recievingBuf:
        if(event & except)
        {
            tracef("recv FAILED");
            m_state = ready;
            // TODO: make callback
            break;
        }
        if(event & read)
        {
            recvBufLoop();
        }
        break;
    };
    return 0;
}

void CTcpSock::deleteSock(void)
{
    close();
    m_intStatus = deleteEvent;
}

/* ------------------------------------------- */

⌨️ 快捷键说明

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