c++——正向代理

c++——正向代理

在这里插入图片描述

  • 代理端作为客户端的监听端口、目的端的客户端口
  • 正向代理B就像中转站,只做信息转发

实现思路

  1. 监听客户端的连接,如果有客户端连上来,代理程序向目标端发起连接请求,建立连接。
  2. 不管哪个socket连接收到了报文,原封不动的发给对端。
/*inetd.cpp*/
#include <sys/epoll.h>
#include <signal.h>
#include <string.h>
#include <sys/socket.h>
#include <iostream>
#include <fcntl.h>
#include <vector>
#include <poll.h>
#include <unistd.h>
#include  <netdb.h>

struct st_route{ // 正向代理路由结构体
        int listenport;	// 监听端口
        char* dstip;	// 目的ip
        int dstport;	// 目的端口
        int listensock;	// 监听sock文件描述符
} stroute;

int epollfd;
// vector<struct st_route> vroute; // 如果有多个转发需求

int initsocket(int port);

int conntodst(char* ip, int port);

int clientvec[2048]; // 建立端口对
/* 如 客户端fd:clientfd		目的端fd:dspfd
	clientvec[clientfd] = dspfd
	clientvec[dspfd] = clientfd
*/

void EXIT(int sig);

int main(int argv, char** argc){

        for(int i = 0; i < 64; i++){signal(i, SIG_IGN);}
        signal(2, EXIT); signal(15, EXIT);

        if(argv != 4){printf("Error argc! ./inetd listenport dstip dstport \n"); return -1;}
        stroute.listenport = atoi(argc[1]);
        stroute.dstip = argc[2];
        stroute.dstport = atoi(argc[3]);
        if((stroute.listensock = initsocket(stroute.listenport)) < 0){perror("failed listen.\n"); return -1;}
        epollfd = epoll_create(1);
        struct epoll_event ev;
        ev.events = EPOLLIN;
        ev.data.fd = stroute.listensock;
        epoll_ctl(epollfd, EPOLL_CTL_ADD, stroute.listensock, &ev);
        struct epoll_event Evs[10];
        while(true){
                int infds = epoll_wait(epollfd, Evs, 10, -1);
                if(infds < 0){printf("epoll failed\n"); return -1;}
                for(int i = 0; i < infds; i++){
                        if(Evs[i].data.fd == stroute.listensock){ // 监听事件
                            	// 连接客户端
                                struct sockaddr_in client_addr;
                                socklen_t len = sizeof(client_addr);
                                int srcsockfd;
                                if ((srcsockfd = accept(Evs[i].data.fd, (struct sockaddr*)&client_addr, &len)) < 0){perror("error accept.\n"); return -1;}
								
                            	// 向目的端发送连接
                                int dstsockfd;
                                if((dstsockfd = conntodst(stroute.dstip, stroute.dstport)) < 0) {perror("error conntodst\n"); return -1;}
                            
                            	// 加入epoll
                                ev.data.fd = srcsockfd; ev.events = EPOLLIN;
                                epoll_ctl(epollfd, EPOLL_CTL_ADD, srcsockfd, &ev);
                                ev.data.fd = dstsockfd; ev.events = EPOLLIN;
                                epoll_ctl(epollfd, EPOLL_CTL_ADD, dstsockfd, &ev);
                            	// 加入clientvec
                                clientvec[srcsockfd] = dstsockfd; clientvec[dstsockfd] = srcsockfd;
                        }else{
                            	// 接收一端信息并发送给另一端
                                char buffer[2048];
                                int buflen = 0;
                                memset(&buffer, 0, sizeof(buffer));
                                if((buflen = recv(Evs[i].data.fd, buffer, sizeof(buffer), 0)) <= 0){ // 连接断开,关闭连接
                                        printf("client(%d, %d) disconnect\n", Evs[i].data.fd, clientvec[Evs[i].data.fd]);
                                        close(Evs[i].data.fd);
                                        close(clientvec[Evs[i].data.fd]);
                                        clientvec[clientvec[Evs[i].data.fd]] = 0;
                                        clientvec[Evs[i].data.fd] = 0;
                                        continue;
                                }
                                send(clientvec[Evs[i].data.fd], buffer, buflen, 0);

                        }
                }
        }


        return 0;
}


int initsocket(int port){ // 初始化监听端口
        int sockfd;
        int opt = 1;
        if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){return -1;}
        setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
        struct sockaddr_in serveraddr;
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
        serveraddr.sin_port = htons(port);
        if(bind(sockfd, (struct sockaddr *)& serveraddr, sizeof(struct sockaddr)) < 0){perror("bind failed.\n");close(sockfd);return -1;}
        if(listen(sockfd, 10) != 0) {perror("listen failed.\n");close(sockfd);return -1;}
        fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK); // sock非阻塞
        return sockfd;
}


int conntodst(char* ip, int port){ // 连接目的端口

        int sockfd;
        int opt = 1;
        if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){return -1;}
        setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
        struct sockaddr_in servaddr;
        memset(&servaddr, 0, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(port);
        struct hostent *h;
        if((h = gethostbyname(ip)) == 0){close(sockfd); return -1;}
        memcpy(&servaddr.sin_addr, h->h_addr, h->h_length);
        if(connect(sockfd, (struct sockaddr*)&servaddr, sizeof(struct sockaddr)) < 0){
                perror("error connect.\n");
                close(sockfd);
                return -1;
        }
        fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK); // sock非阻塞
        return sockfd;
}

void EXIT(int sig){ // 信号处理函数
        printf("Exit! Signal=%d\n", sig);
        for(int i = 0; i < 2048; i++){
                if(clientvec[i]>0){close(clientvec[i]);}
        }
        if(stroute.listensock>0){close(stroute.listensock);}
        close(epollfd);
        exit(0);
}

结果

  • 代理端
    在这里插入图片描述
  • 远程目的端
    在这里插入图片描述
  • 本地客户端
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
桥接模式是一种结构型设计模式,它将抽象和实现分离,使它们可以独立地变化。桥接模式的核心思想是将一个大类或一组类分解成抽象和实现两个独立的维度,使它们可以独立地变化和扩展,同时通过桥接来将它们连接起来。 在C++中,桥接模式通常通过虚函数实现。抽象部分通过基类定义接口,而实现部分通过派生类实现具体的功能。通过将抽象部分的指针作为参数传递给实现部分的函数,就可以实现两个部分的连接。 下面是一个简单的桥接模式的C++示例: ```c++ class Implementor { public: virtual void operation() = 0; virtual ~Implementor() {} }; class ConcreteImplementorA : public Implementor { public: void operation() override { // 具体的实现A } }; class ConcreteImplementorB : public Implementor { public: void operation() override { // 具体的实现B } }; class Abstraction { public: Abstraction(Implementor* implementor) : m_implementor(implementor) {} virtual void operation() = 0; virtual ~Abstraction() {} protected: Implementor* m_implementor; }; class RefinedAbstraction : public Abstraction { public: RefinedAbstraction(Implementor* implementor) : Abstraction(implementor) {} void operation() override { m_implementor->operation(); // 其他操作 } }; int main() { Implementor* implementorA = new ConcreteImplementorA(); Implementor* implementorB = new ConcreteImplementorB(); Abstraction* abstractionA = new RefinedAbstraction(implementorA); Abstraction* abstractionB = new RefinedAbstraction(implementorB); abstractionA->operation(); abstractionB->operation(); delete abstractionA; delete abstractionB; delete implementorA; delete implementorB; return 0; } ``` 在上面的示例中,Implementor是实现部分的抽象基类,ConcreteImplementorA和ConcreteImplementorB是具体的实现类。Abstraction是抽象部分的基类,RefinedAbstraction是抽象部分的具体实现类。在main函数中,我们创建了不同的Implementor和Abstraction对象,并通过它们来完成不同的操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Y (O - O) Y

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

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

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

打赏作者

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

抵扣说明:

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

余额充值