socket端口数据转发

51 篇文章 3 订阅

参考文章:http://blog.csdn.net/wangyi_lin/article/details/9277717?utm_source=tuicool

 灵感来源于lcx.exe

---------------------------------------------------------------------------

先说下我的需求:

因工作的需要,别的电脑在访问我的电脑的80端口时,我希望其访问的其实是某台设备的80端口,

因为我的电脑根本没有web服务,提供web服务的其实是某台设备,公司有很多台设备哈。。。

而别的电脑只能访问我的电脑,不能直接访问设备。。。

为了别的电脑能通过我的电脑访问到设备,因此我写了这个程序。。。

------------------------------------------------------------------------------------------------------

该demo程序我测试了百度、人人网、博客园,都可以通过我的程序进行转发访问,

说明我的想法真的可以实现了。。。

为了测试,需要修改以下文件:

C:\Windows\System32\drivers\etc\hosts

如我的为:

192.168.1.3 www.renren.com
192.168.1.3 www.baidu.com
192.168.1.3 www.cnblogs.com


-------------------------------------------------------------------------------------

程序效果如下:


-----------------------------------------------------------------------------------------------------------

关键代码如下:

// 80端口监听线程
void CTranspondDlg::ThreadListenPort80( void )
{
    ShowMessage("进入ThreadListenPort80");

    SOCKET skServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (INVALID_SOCKET == skServer)
    {
        ShowMessage("创建socket失败");
        m_bIsStop = true;
    }
    SOCKADDR_IN skSvrAddr;
    skSvrAddr.sin_family = AF_INET;
    skSvrAddr.sin_port = htons(80);
    skSvrAddr.sin_addr.S_un.S_addr = ADDR_ANY;
    if (bind(skServer, (struct sockaddr*)&skSvrAddr, sizeof(skSvrAddr)) == SOCKET_ERROR)
    {
        ShowMessage("80端口绑定socket失败");
        m_bIsStop = true;
    }
    if (listen(skServer, SOMAXCONN) == SOCKET_ERROR)
    {
        ShowMessage("80端口监听socket失败");
        m_bIsStop = true;
    }
    else
    {
        ShowMessage("socket监听80端口成功,等待客户连接...");
    }

    CString strLog;
    while(!m_bIsStop)
    {
        if (SOCKET_Select(skServer, 500, TRUE))
        {
            SOCKET skClient;
            int iAddrLen = sizeof(SOCKADDR_IN);
            SOCKADDR_IN skAddrClient;
            skClient = accept(skServer, (sockaddr*)&skAddrClient, &iAddrLen);
            strLog.Format("有客户连接:%s:%d", inet_ntoa(skAddrClient.sin_addr), ntohs(skAddrClient.sin_port));
            ShowMessage(strLog);

            // 连接真正的web服务器
            SOCKET skWeb = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
            if (skWeb == skServer)
            {
                ShowMessage("创建web socket失败");
                m_bIsStop = true;
                break;
            }
            SOCKADDR_IN skAddrWeb;
            skAddrWeb.sin_family = AF_INET;
            skAddrWeb.sin_port = htons(80);
            skAddrWeb.sin_addr.S_un.S_addr = inet_addr("180.97.33.108"); // 百度
            //skAddrWeb.sin_addr.S_un.S_addr = inet_addr("220.181.181.224"); // 人人
            //skAddrWeb.sin_addr.S_un.S_addr = inet_addr("42.121.252.58"); // cnblogs
            if (connect(skWeb, (sockaddr*)&skAddrWeb, sizeof(sockaddr)) == SOCKET_ERROR)
            {
                ShowMessage("连接web服务器失败");
                m_bIsStop = true;
                break;
            }

            // 开启数据转发线程
            TranspondSocket transpondSocket;
            transpondSocket.pThis = this;
            transpondSocket.skClient = skClient;
            transpondSocket.skServer = skWeb;
            HANDLE hTmp = (HANDLE)_beginthreadex(NULL, 0, ThreadTranspondDataProxy, &transpondSocket, 0, NULL);
            CloseHandle(hTmp);
            hTmp = NULL;
        }
    }

    closesocket(skServer);
    ShowMessage("退出ThreadListenPort80");
}

----------------------------------------------------------------
// 数据转发线程
void CTranspondDlg::ThreadTranspondData( LPVOID pvParam )
{
    ShowMessage("进入ThreadTranspondData");
    CString strLog;
    TranspondSocket *pTS = (TranspondSocket*)pvParam;
    if (pTS == NULL)
    {
        ShowMessage("ThreadTranspondData 参数错误");
        ShowMessage("退出ThreadTranspondData");
        return;
    }

    // SIO_KEEPALIVE_VALS 机制
    //structtcp_keepalive {
    //    ULONGonoff ;          // 是否开启keepalive
    //    ULONGkeepalivetime ;  // 多长时间(ms)没有数据就开始send心跳包
    //    ULONGkeepaliveinterval ; // 每隔多长时间(ms)send一个心跳包,
    //                             // 发5次(2000 XP 2003默认), 10次(Vista后系统默认)
    //};
    
    //tcp_keepalive inKeepAlive = {0};
    //tcp_keepalive outKeepAlive = {0};
    //unsigned long ulInLen = sizeof(tcp_keepalive);
    //unsigned long ulOutLen = sizeof(tcp_keepalive);
    //unsigned long ulBytesReturn = 0;
    //inKeepAlive.onoff = 1;
    //inKeepAlive.keepaliveinterval = 1000; //单位为毫秒
    //inKeepAlive.keepalivetime = 1000;     //单位为毫秒
    //int iRet = WSAIoctl(pTS->skClient, SIO_KEEPALIVE_VALS, (LPVOID)&inKeepAlive, ulInLen,  (LPVOID)&outKeepAlive, ulOutLen, &ulBytesReturn, NULL, NULL);
    //if (iRet != 0)
    //{
    //    strLog.Format("WSAIoctl错误, ErrCode=%d", WSAGetLastError());
    //    ShowMessage(strLog);
    //    ShowMessage("退出ThreadTranspondData");
    //    return;
    //}
    //iRet = WSAIoctl(pTS->skClient, SIO_KEEPALIVE_VALS, (LPVOID)&inKeepAlive, ulInLen,  (LPVOID)&outKeepAlive, ulOutLen, &ulBytesReturn, NULL, NULL);
    //if (iRet != 0)
    //{
    //    strLog.Format("WSAIoctl错误, ErrCode=%d", WSAGetLastError());
    //    ShowMessage(strLog);
    //    ShowMessage("退出ThreadTranspondData");
    //    return;
    //}

    bool bIsExit = false;
    int iRecvSum = 0;
    int iSendSum = 0;
    char szBuf[4096] = {0};
    DWORD dwErroCode = 0;
    while(!m_bIsStop)
    {
        if (bIsExit)
        {
            break;
        }
        memset(szBuf, 0, sizeof(szBuf));
        iRecvSum = 0;
        iSendSum = 0;

        // 接收客户端数据
        while(SOCKET_Select(pTS->skClient, 100, TRUE))
        {
            iRecvSum = recv(pTS->skClient, szBuf, sizeof(szBuf), 0);
            dwErroCode = WSAGetLastError();

            // 判断客户端是否断开
            if (WSAGetLastError() == WSAECONNRESET)
            {
                ShowMessage("客户端断开");
                bIsExit = true;
                break;
            }
            if (iRecvSum <= 0)
            {
                strLog.Format("没有收到服客户端数据:dwErroCode=%d", dwErroCode);
                ShowMessage(strLog);
                bIsExit = true;
                break;
            }
            strLog.Format("收到客户端数据:iReadSum=%d", iRecvSum);
            ShowMessage(strLog);
            strLog.Format("%s", szBuf);
            ShowMessage(strLog);

            // 将客户请求的数据发给真正的服务器
            iSendSum = send(pTS->skServer, szBuf, iRecvSum, 0);
            strLog.Format("给服务器发送数据:iSendSum=%d, ErrCode=%d", iSendSum, WSAGetLastError());
            ShowMessage(strLog);
        }

        // 接收真正的服务器返回来的数据
        while(SOCKET_Select(pTS->skServer, 100, TRUE))
        {
            iRecvSum = recv(pTS->skServer, szBuf, sizeof(szBuf), 0);
            dwErroCode = WSAGetLastError();

            // 判断服务器是否断开
            if (WSAGetLastError() == WSAECONNRESET)
            {
                ShowMessage("服务器断开");
                bIsExit = true;
                break;
            }

            if (iRecvSum <= 0)
            {
                strLog.Format("没有收到服务器数据:dwErroCode=%d", dwErroCode);
                ShowMessage(strLog);
                bIsExit = true;
                break;
            }
            strLog.Format("收到服务器数据:iRecvSum=%d", iRecvSum);
            ShowMessage(strLog);
            strLog.Format("%s", szBuf);
            ShowMessage(strLog);

            // 将服务器数据发给客户端
            iSendSum = send(pTS->skClient, szBuf, iRecvSum, 0);
            strLog.Format("发送给客户端数据:iSendSum=%d, ErrCode=%d", iSendSum, WSAGetLastError());
            ShowMessage(strLog);
        }
    }

    closesocket(pTS->skClient);
    closesocket(pTS->skServer);
    ShowMessage("退出ThreadTranspondData");
}


 

------------------------------------------------------------------------

唯一的缺点就是,客户端掉线的检测机制不是很好,留给需要的人去完善吧。。。

程序VS2010源码工程下载:

 http://download.csdn.net/detail/friendan/8684207

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

friendan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值