您现在的位置是:首页 >学无止境 >C++深入的网络编程网站首页学无止境

C++深入的网络编程

MAX在码字 2024-06-19 00:01:02
简介C++深入的网络编程

介绍

在本文中,我们将介绍用于处理套接字的基本基元,这些基元在 2.2 版的 winsock0.h 文件中定义。

我们还将介绍两个有用的实用程序,它们解决了各种网络任务。

当然,我们可以使用 Microsoft 基础类 (MFC) 进行异步编程,但是,我们的方法更适合系统网络编程。学习交流Q群833065897

因此,本文介绍的程序是一个实用程序,它ping用户定义的协议并测量连接速度。CPing

另一个例子是,在SOCKS-5协议上为互联网中继聊天(IRC)等信使代理隧道算法。CSocks

背景

本文将根据项目的征求意见(RFC)标准进行研究,因为它使用SOCKS-4 / 5互联网TCP协议的命令顺序,因此在用户或更高级别上运行,而不是在系统级别和协议上运行的相同“ping”实用程序,如互联网控制消息协议(ICMP)。CSocks

因此,我们在项目中引入了相同的ping实用程序,该实用程序按原样工作,以测试超文本传输协议(HTTP)和其他在用户定义级别上运行的功能。CPing

使用代码

在继续描述使用套接字进行网络编程的编程技术之前,我们将描述 API 的几个功能:Winsock

  • socket()- 创建套接字实体
  • send()- 将数据包发送到套接字的端点
  • recv()- 从同一端点接收数据包
  • setsockopt()- 设置套接字选项,如超时等。
  • connect()- 连接到与网络程序工作的主机不同的套接字端点
  • select()- 选择从端点开始执行操作的当前时间活动套接字

让我们继续初始化套接字库,如下所示:CPing

C++

#include <windows.h>#include <winsock2.h> // necessary#include "CPing.h"#include <string.h>#include <stdio.h>#include <stdlib.h>

CPing::CPing()

{

    iTimeOut = 1000;

    iBytesToRecv = 0;

    iLastError = WSAStartup (MAKEWORD(2,0),&wsadata); // initialize Windows Sockets    strcpy (szNoop, NOOP);

}

CPing::~CPing()

{

    WSACleanup(); // clean up the Windows Sockets cache}

该类定义如下:CPing

C++

收缩 ▲   

#ifndef __CPING_CLASS#define __CPING_CLASS#define MAX_SENDS 1111111#define NOOP "NOOP"typedef struct {

    unsigned int iTimeSend; // measured time to send TCP packet    unsigned int iTimeRecv; // measured time to receive TCP packet    unsigned int iTotalSent, iTotalRecvd; // total number of bytes sent and received    unsigned int iPort; // TCP protocol port} pingstore;

class CPing

{

public:

    CPing();

    ~CPing();

    char szNoop[256];

    int iLastError, iTotalRes, iBytesToRecv;

    unsigned int iTimeOut, iTotalSent, iTotalRecvd;

    unsigned int PingContinuous

             (char* szHost, unsigned int iPort, unsigned int iPackets);

    unsigned int PingConnective

             (char* szHost, unsigned int iPort, unsigned int iPackets);

    pingstore* Res;

private:

    WSADATA wsadata;

};

#endif

为了足够清楚,我们必须提供一个在实用程序中支持 Windows 套接字的情况下使用面向对象编程的示例,如下所示:CPing

C++

收缩 ▲   

unsigned int CPing::PingContinuous

         (char* szHost, unsigned int iPort, unsigned int iPackets)

{

    struct hostent* host = NULL;

    struct sockaddr_in saddr;

    unsigned int s = 0;

    unsigned int dw1, dw2, dw3;

    char szBuffer[256];

    if (!iBytesToRecv) iBytesToRecv = strlen(szNoop);

    if (iPackets>MAX_SENDS) return (0);

    free (Res);

    Res = (pingstore*)malloc (sizeof(pingstore)*iPackets);

    memset (Res, 0, sizeof(pingstore)*iPackets);

    s = socket(AF_INET, SOCK_STREAM, 0);

    if (!s) return (0);

    setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&iTimeOut, sizeof(iTimeOut));

    setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char*)&iTimeOut, sizeof(iTimeOut));

    host = gethostbyname (szHost);

    if (host==NULL) return (0);

    saddr.sin_family = AF_INET;

    saddr.sin_port = htons(iPort);

    saddr.sin_addr = *((struct in_addr*)host->h_addr);

    if (connect (s,(struct sockaddr*)&saddr, sizeof(saddr)) == -1) return (0);    

    for (int i=0;i<iPackets;i++)

    {

        iTotalRes++;

        sprintf (szBuffer, "%s ", szNoop);

        dw1 = GetTickCount();

        int iSent = send (s, szBuffer, strlen(szBuffer), 0);

        dw2 = GetTickCount();

        int iRecv = recv (s, szBuffer, iBytesToRecv, 0);

        dw3 = GetTickCount();

        Res[i].iPort = iPort;

        Res[i].iTimeSend = dw2-dw1;

        Res[i].iTimeRecv = dw3-dw2;

        Res[i].iTotalSent = ((iSent==SOCKET_ERROR)?0:iSent);

        Res[i].iTotalRecvd = ((iRecv==SOCKET_ERROR)?0:iRecv);

        if (iRecv<=0)

        {

            closesocket (s);

            return ((iTotalRes)?1:0);

        }

    }

    closesocket (s);

    return (1);

}

另一个示例,如用于在 SOCKS-5 协议上代理的网络实用程序,定义如下:CSocks

C++

收缩 ▲   

#ifndef __CSOCKS_HEADER#define __CSOCKS_HEADER#include "common.h"#include "cauth.h"class CSocks {

private:

    

public:

    PSOCKSNOTIFYPROC pNotifyProc;

    u_short uPort, mode;

    u_int uAccept;

    u_long LastError;

    CSocksBasicAuth* basicauth = NULL;

    CSocks() {

        uAccept = 0;

        mode = SOCKS_MODE_TCP;

        uPort = SOCKS_DEF_PORT;

        LastError = SOCKS_ERROR_NONE;

        pNotifyProc = NULL;

    };

    ~CSocks() {

        if(uAccept) closesock(uAccept);

    };

    bool DNSAddrLookup(char* sHost, struct in_addr* addr);

    bool StartChaining();

    bool SocksTCPTunneling(u_int sres, u_int sdest);

    bool SocksUDPTunneling(void* sadest, char* sData, u_int len);

    bool PrepareListening();

    char* GetLastError();

    virtual bool ForceConnection(u_int sock) = 0;

};

#endif

我们提出这个类作为网络数据通过中介套接字时网络操作(如隧道)的示例实现 - 这个概念主要用于代理软件,此操作定义如下(并且是执行隧道操作的套接字):sres sdest

C++

收缩 ▲   

bool CSocks::SocksTCPTunneling(u_int sres, u_int sdest)

{

    register u_int sockr, sockw, ret;

    register u_int uread, uwrote;

    char szBuffer[1024];

    struct fd_set fd;

    struct timeval tv = {0,0};

    

    do

    {

        FD_ZERO(&fd);

        FD_SET(sres,&fd);

        FD_SET(sdest,&fd);

        

        if((ret = select(0,&fd,NULL,NULL,&tv))>0 && VALID_SOCKET(ret))

        {

            if(FD_ISSET(sres,&fd))

            {

                sockr = sres;

                sockw = sdest;

            }

            else

            {

                sockr = sdest;

                sockw = sres;

            }

            uread = recv(sockr,szBuffer,1023,0);

            

            if (uread >= 1023) break;

            

            szBuffer[uread] = 0;

            uwrote = 0;

            if(!VALID_SOCKET(uread) || uread==0) break;

            while(uwrote<uread)

            {

                ret = send(sockw,szBuffer+uwrote,uread-uwrote,0);

                if(!VALID_SOCKET(ret)) goto __quit;

                uwrote += ret;

            }

        }

        FD_ZERO(&fd);

        FD_SET(sres,&fd);

        FD_SET(sdest,&fd);

        if(select(0,NULL,NULL,&fd,&tv)>0) break;

    } while(1);

    

__quit:

    return(true);

}

这就是现在的全部内容,可以从我们的存储库中研究其他次要过程和功能,但是,以上所有内容都代表了必要的知识,以便在C++编程语言中使用系统级别的套接字。学习交流Q群833065897

兴趣点 学习交流Q群833065897

因此,我们已经学会了如何为特定的网络任务采用套接字层模型,以获得更好的性能和更深入的功能和评估。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。