您现在的位置是:首页 >学无止境 >C++深入的网络编程网站首页学无止境
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
因此,我们已经学会了如何为特定的网络任务采用套接字层模型,以获得更好的性能和更深入的功能和评估。