中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

昆明做網(wǎng)站最好的小說網(wǎng)站排名

昆明做網(wǎng)站,最好的小說網(wǎng)站排名,企業(yè)網(wǎng)站招聘可以怎么做,灰色網(wǎng)站怎么做1 概念 1.1 反向代理概念 反向代理是指以代理服務器來接收客戶端的請求,然后將請求轉(zhuǎn)發(fā)給內(nèi)部網(wǎng)絡(luò)上的服務器,將從服務器上得到的結(jié)果返回給客戶端,此時代理服務器對外表現(xiàn)為一個反向代理服務器。 對于客戶端來說,反向代理就相當于…

?

1 概念

?

1.1 反向代理概念

  • 反向代理是指以代理服務器來接收客戶端的請求,然后將請求轉(zhuǎn)發(fā)給內(nèi)部網(wǎng)絡(luò)上的服務器,將從服務器上得到的結(jié)果返回給客戶端,此時代理服務器對外表現(xiàn)為一個反向代理服務器。

  • 對于客戶端來說,反向代理就相當于目標服務器,只需要將反向代理當作目標服務器一樣發(fā)送請求就可以了,并且客戶端不需要進行任何設(shè)置。

1.2 特點

  • 反向代理是代理服務器,為服務器收發(fā)請求,使真實服務器對客戶端不可見。

原文鏈接:https://blog.csdn.net/Dax1_/article/details/124652162

1.3 反向代理場景

66efe5f8d1f5452e91b585a637f7f24b.png

  • 正向代理:A可以訪問B,B可以訪問C。如果A要訪問C,那么要在B上面部署正向代理模塊。

  • 反向代理:A可以訪問B,C可以訪問B,B不能訪問A和C;如果A要訪問C,可以用反向代理。

完整的反向代理圖如下所示:

9f3a3b0fe7484b03b908d8cf51f1db7b.png

不適用代理的情況下,外網(wǎng)不能訪問企業(yè)內(nèi)網(wǎng)的服務器;如果希望訪問企業(yè)內(nèi)網(wǎng),必須要使用反向代理,如果要使用反向代理,企業(yè)必須要有一個公網(wǎng)的服務器,公網(wǎng)的IP。

  • 正向代理只有一個模塊一個服務程序;
  • 而反向代理有兩個模塊兩個服務程序:外網(wǎng)模塊和內(nèi)網(wǎng)模塊。

2 反向代理實現(xiàn)

2.1 反向代理基本思路

598f3677060d4c90b86d26318bcdc535.png

  1. 服務程序啟動的時候,內(nèi)網(wǎng)模塊向外網(wǎng)模塊發(fā)起一個TCP連接,建立一條傳輸通道(稱為命令通道);

  2. 之后外網(wǎng)模塊讀取路由參數(shù)配置文件,外網(wǎng)模塊需要監(jiān)聽5122,5123,5128三個端口;

  3. 用戶1連接了外網(wǎng)服務器的5122端口,外網(wǎng)模塊通過命令通道告訴內(nèi)網(wǎng)模塊幫我連192.168.168.1.4的22端口;

  4. 內(nèi)網(wǎng)模塊向外網(wǎng)模塊發(fā)起TCP連接,建立一條傳輸通道,同時內(nèi)網(wǎng)模塊連接192.168.1.4 22,整個鏈路就建立起來了。

外網(wǎng)模塊外網(wǎng)程序:

  • 外網(wǎng)模塊沒有主動的向任何服務器發(fā)起連接。
  • 外網(wǎng)程序沒有為命令通道的socket準備epoll事件(因為命令通道不需要監(jiān)聽,只有外網(wǎng)程序向內(nèi)網(wǎng)發(fā)送命令,內(nèi)網(wǎng)程序并不會向外網(wǎng)程序發(fā)送命令。)。

內(nèi)網(wǎng)模塊內(nèi)網(wǎng)程序:

  • 內(nèi)網(wǎng)程序非阻塞socket命令通道建立之后,再設(shè)置為非阻塞的,加入epoll事件。
  • 此時,內(nèi)網(wǎng)模塊與外網(wǎng)模塊都進入事件循環(huán),外網(wǎng)程序監(jiān)聽著路由配置文件的端口可以開始接受用戶客戶端的連接請求了;內(nèi)網(wǎng)程序epoll中只有命令通道的socket,內(nèi)網(wǎng)程序也做好了準備接收外網(wǎng)程序的命令。

2.2 框架流程圖

2fedc1b2e17646b3bd2436058a58c490.png

2.3 反向代理框架實現(xiàn)

rinetd.cpp外網(wǎng)模塊

/** 程序名:rinetd.cpp,反向網(wǎng)絡(luò)代理服務程序-外網(wǎng)端。* 作者:張咸武
*/
#include "_public.h"
using namespace idc;// 代理路由參數(shù)的結(jié)構(gòu)體。
struct st_route
{int    srcport;           // 源端口。char dstip[31];        // 目標主機的地址。int    dstport;          // 目標主機的端口。int    listensock;      // 監(jiān)聽源端口的socket。
}stroute;
vector<struct st_route> vroute;       // 代理路由的容器。
bool loadroute(const char *inifile);  // 把代理路由參數(shù)加載到vroute容器。int initserver(int port);     // 初始化服務端的監(jiān)聽端口。int epollfd=0;                  // epoll的句柄。
int tfd=0;                         // 定時器的句柄。#define MAXSOCK  1024
int clientsocks[MAXSOCK];       // 存放每個socket連接對端的socket的值。
int clientatime[MAXSOCK];       // 存放每個socket連接最后一次收發(fā)報文的時間。
string clientbuffer[MAXSOCK]; // 存放每個socket發(fā)送內(nèi)容的buffer。int cmdlistensock=0;                // 命令通道監(jiān)聽的socket。
int cmdconnsock=0;                 // 命令通道連接的socket。void EXIT(int sig);                      // 進程退出函數(shù)。clogfile logfile;// cpactive pactive;                        // 進程心跳。int main(int argc,char *argv[])
{if (argc != 4){printf("\n");printf("Using :./rinetd logfile inifile cmdport\n\n");printf("Sample:./rinetd /tmp/rinetd.log /etc/rinetd.conf 5001\n\n");printf("        /project/tools/bin/procctl 5 /project/tools/bin/rinetd /tmp/rinetd.log /etc/rinetd.conf 5001\n\n");printf("logfile 本程序運行的日志文件名。\n");printf("inifile 代理路由參數(shù)配置文件。\n");printf("cmdport 與內(nèi)網(wǎng)代理程序的通訊端口。\n\n");return -1;}// 關(guān)閉全部的信號和輸入輸出。// 設(shè)置信號,在shell狀態(tài)下可用 "kill + 進程號" 正常終止些進程。// 但請不要用 "kill -9 +進程號" 強行終止。closeioandsignal(); signal(SIGINT,EXIT); signal(SIGTERM,EXIT);// 打開日志文件。if (logfile.open(argv[1])==false){printf("打開日志文件失敗(%s)。\n",argv[1]); return -1;}// pactive.addpinfo(30,"rinetd");       // 設(shè)置進程的心跳超時間為30秒。// 把代理路由參數(shù)加載到vroute容器。if (loadroute(argv[2])==false) return -1;logfile.write("加載代理路由參數(shù)成功(%d)。\n",vroute.size());// 初始化命令通道的監(jiān)聽端口。if ( (cmdlistensock=initserver(atoi(argv[3]))) < 0 ){   logfile.write("initserver(%s) failed.\n",argv[3]); EXIT(-1);}// 等待內(nèi)網(wǎng)程序的連接請求,cmdlistensock是阻塞的,并且沒有交給epoll。struct sockaddr_in client;socklen_t len = sizeof(client);cmdconnsock = accept(cmdlistensock,(struct sockaddr*)&client,&len);if (cmdconnsock < 0){logfile.write("accept() failed.\n"); EXIT(-1);}logfile.write("與內(nèi)部的命令通道已建立(cmdconnsock=%d)。\n",cmdconnsock);// 初始化服務端用于監(jiān)聽外網(wǎng)的socket。for (int ii=0;ii<vroute.size();ii++){if ( (vroute[ii].listensock=initserver(vroute[ii].srcport)) < 0 ){logfile.write("initserver(%d) failed.\n",vroute[ii].srcport); EXIT(-1);}// 把監(jiān)聽socket設(shè)置成非阻塞。fcntl(vroute[ii].listensock,F_SETFL,fcntl(vroute[ii].listensock,F_GETFD,0)|O_NONBLOCK);}// 創(chuàng)建epoll句柄。epollfd=epoll_create(1);struct epoll_event ev;  // 聲明事件的數(shù)據(jù)結(jié)構(gòu)。// 為監(jiān)聽外網(wǎng)的socket準備可讀事件。for (int ii=0;ii<vroute.size();ii++){ev.events=EPOLLIN;                       // 讀事件。ev.data.fd=vroute[ii].listensock;  epoll_ctl(epollfd,EPOLL_CTL_ADD,vroute[ii].listensock,&ev);   // 把監(jiān)聽外網(wǎng)的socket的讀事件加入epollfd中。}// 創(chuàng)建定時器。tfd=timerfd_create(CLOCK_MONOTONIC,TFD_NONBLOCK|TFD_CLOEXEC);  // 創(chuàng)建timerfd。struct itimerspec timeout;memset(&timeout,0,sizeof(struct itimerspec));timeout.it_value.tv_sec = 20;                  // 超時時間為20秒。timeout.it_value.tv_nsec = 0;timerfd_settime(tfd,0,&timeout,NULL);  // 開始計時。// 為定時器準備事件。ev.events=EPOLLIN;   ev.data.fd=tfd;epoll_ctl(epollfd,EPOLL_CTL_ADD,tfd,&ev);       // 把定時器的讀事件加入epollfd中。struct epoll_event evs[10];     // 存放epoll返回的事件。while (true){// 等待監(jiān)視的socket有事件發(fā)生。int infds=epoll_wait(epollfd,evs,10,-1);// 返回失敗。if (infds < 0) { logfile.write("epoll() failed。"); EXIT(-1); }// 遍歷epoll返回的已發(fā)生事件的數(shù)組evs。for (int ii=0;ii<infds;ii++){// 如果定時器的時間已到,有三件事要做:1)更新進程的心跳;2)向命令通道發(fā)送心跳報文;3)清理空閑的客戶端socket。if (evs[ii].data.fd==tfd){// logfile.write("定時器時間已到。\n");timerfd_settime(tfd,0,&timeout,0);  // 重新開始計時。// pactive.uptatime();        // 1)更新進程心跳;// 2)向命令通道發(fā)送心跳報文;char buffer[256];strcpy(buffer,"<activetest>");if (send(cmdconnsock,buffer,strlen(buffer),0)<=0){logfile.write("與內(nèi)網(wǎng)程序的命令通道已斷開。\n"); EXIT(-1);}// 3)清理空閑的客戶端socket。for (int jj=0;jj<MAXSOCK;jj++){// 如果客戶端socket空閑的時間超過80秒就關(guān)掉它。if ( (clientsocks[jj]>0) && ((time(0)-clientatime[jj])>80) ){logfile.write("client(%d,%d) timeout。\n",clientsocks[jj],clientsocks[clientsocks[jj]]);close(clientsocks[jj]);  close(clientsocks[clientsocks[jj]]);// 把數(shù)組中對端的socket置空,這一行代碼和下一行代碼的順序不能亂。clientsocks[clientsocks[jj]]=0;// 把數(shù)組中本端的socket置空,這一行代碼和上一行代碼的順序不能亂。clientsocks[jj]=0;}}continue;}// 如果發(fā)生事件的是監(jiān)聽的listensock,表示外網(wǎng)有新的客戶端連上來。int jj=0;for (jj=0;jj<vroute.size();jj++){if (evs[ii].data.fd==vroute[jj].listensock){// 從已連接隊列中獲取一個已準備好的外網(wǎng)客戶端的socket。struct sockaddr_in client;socklen_t len = sizeof(client);int srcsock = accept(vroute[jj].listensock,(struct sockaddr*)&client,&len);if (srcsock<0) break;if (srcsock>=MAXSOCK) {logfile.write("連接數(shù)已超過最大值%d。\n",MAXSOCK); close(srcsock); break;}// 通過命令通道向內(nèi)網(wǎng)程序發(fā)送命令,把路由參數(shù)傳給它。char buffer[256];memset(buffer,0,sizeof(buffer));sprintf(buffer,"<dstip>%s</dstip><dstport>%d</dstport>",vroute[jj].dstip,vroute[jj].dstport);if (send(cmdconnsock,buffer,strlen(buffer),0)<=0){logfile.write("與內(nèi)網(wǎng)的命令通道已斷開。\n"); EXIT(-1);}// 接受內(nèi)網(wǎng)程序的連接,這里的accept()是阻塞的。int dstsock=accept(cmdlistensock,(struct sockaddr*)&client,&len);if (dstsock<0) { close(srcsock); break; }if (dstsock>=MAXSOCK){logfile.write("連接數(shù)已超過最大值%d。\n",MAXSOCK); close(srcsock); close(dstsock); break;}// 把內(nèi)網(wǎng)和外網(wǎng)客戶端的socket對接在一起。// 為新連接的兩個socket準備可讀事件,并添加到epoll中。ev.data.fd=srcsock; ev.events=EPOLLIN;epoll_ctl(epollfd,EPOLL_CTL_ADD,srcsock,&ev);ev.data.fd=dstsock; ev.events=EPOLLIN;epoll_ctl(epollfd,EPOLL_CTL_ADD,dstsock,&ev);// 更新clientsocks數(shù)組中兩端soccket的值和活動時間。clientsocks[srcsock]=dstsock;    clientatime[srcsock]=time(0); clientsocks[dstsock]=srcsock;    clientatime[dstsock]=time(0);logfile.write("accept port %d client(%d,%d) ok。\n",vroute[jj].srcport,srcsock,dstsock);break;}}// 如果jj<vroute.size(),表示事件在上面的for循環(huán)中已被處理。if (jj<vroute.size()) continue;// 如果是客戶端連接的socke有事件,分三種情況:1)客戶端有報文發(fā)過來;2)客戶端連接已斷開;3)有數(shù)據(jù)要發(fā)給客戶端。// 如果從通道一端的socket讀取到了數(shù)據(jù),把數(shù)據(jù)存放在對端socket的緩沖區(qū)中。//  if (evs[ii].events==EPOLLIN)   // 不要這么寫,有讀事件是1,有寫事件是4,如果讀和寫都有,是5。if (evs[ii].events&EPOLLIN)     // 判斷是否為讀事件。 {char buffer[5000];     // 存放從接收緩沖區(qū)中讀取的數(shù)據(jù)。int    buflen=0;          // 從接收緩沖區(qū)中讀取的數(shù)據(jù)的大小。// 從通道的一端讀取數(shù)據(jù)。if ( (buflen=recv(evs[ii].data.fd,buffer,sizeof(buffer),0)) <= 0 ){// 如果連接已斷開,需要關(guān)閉通道兩端的socket。logfile.write("client(%d,%d) disconnected。\n",evs[ii].data.fd,clientsocks[evs[ii].data.fd]);close(evs[ii].data.fd);                                         // 關(guān)閉客戶端的連接。close(clientsocks[evs[ii].data.fd]);                     // 關(guān)閉客戶端對端的連接。clientsocks[clientsocks[evs[ii].data.fd]]=0;       // 把數(shù)組中對端的socket置空,這一行代碼和下一行代碼的順序不能亂。clientsocks[evs[ii].data.fd]=0;                           // 把數(shù)組中本端的socket置空,這一行代碼和上一行代碼的順序不能亂。continue;}// 成功的讀取到了數(shù)據(jù),把接收到的報文內(nèi)容原封不動的發(fā)給通道的對端。// logfile.write("from %d to %d,%d bytes。\n",evs[ii].data.fd,clientsocks[evs[ii].data.fd],buflen);// send(clientsocks[evs[ii].data.fd],buffer,buflen,0);logfile.write("from %d,%d bytes\n",evs[ii].data.fd,buflen);// 把讀取到的數(shù)據(jù)追加到對端socket的buffer中。clientbuffer[clientsocks[evs[ii].data.fd]].append(buffer,buflen);// 修改對端socket的事件,增加寫事件。ev.data.fd=clientsocks[evs[ii].data.fd];ev.events=EPOLLIN|EPOLLOUT;epoll_ctl(epollfd,EPOLL_CTL_MOD,ev.data.fd,&ev);// 更新通道兩端socket的活動時間。clientatime[evs[ii].data.fd]=time(0); clientatime[clientsocks[evs[ii].data.fd]]=time(0);  }// 判斷客戶端的socket是否有寫事件(發(fā)送緩沖區(qū)沒有滿)。if (evs[ii].events&EPOLLOUT){// 把socket緩沖區(qū)中的數(shù)據(jù)發(fā)送出去。int writen=send(evs[ii].data.fd,clientbuffer[evs[ii].data.fd].data(),clientbuffer[evs[ii].data.fd].length(),0);// 以下代碼模擬不能一次發(fā)完全部數(shù)據(jù)的場景。//int ilen;//if (clientbuffer[evs[ii].data.fd].length()>10) ilen=10;//else ilen=clientbuffer[evs[ii].data.fd].length();//int writen=send(evs[ii].data.fd,clientbuffer[evs[ii].data.fd].data(),ilen,0);logfile.write("to %d,%d bytes\n",evs[ii].data.fd,writen);// 刪除socket緩沖區(qū)中已成功發(fā)送的數(shù)據(jù)。clientbuffer[evs[ii].data.fd].erase(0,writen);// 如果socket緩沖區(qū)中沒有數(shù)據(jù)了,不再關(guān)心socket的寫件事。if (clientbuffer[evs[ii].data.fd].length()==0){ev.data.fd=evs[ii].data.fd;ev.events=EPOLLIN;epoll_ctl(epollfd,EPOLL_CTL_MOD,ev.data.fd,&ev);}}}}return 0;
}// 初始化服務端的監(jiān)聽端口。
int initserver(const int port)
{int sock = socket(AF_INET,SOCK_STREAM,0);if (sock < 0){logfile.write("socket(%d) failed.\n",port); return -1;}int opt = 1; unsigned int len = sizeof(opt);setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,len);struct sockaddr_in servaddr;servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(port);if (bind(sock,(struct sockaddr *)&servaddr,sizeof(servaddr)) < 0 ){logfile.write("bind(%d) failed.\n",port); close(sock); return -1;}if (listen(sock,5) != 0 ){logfile.write("listen(%d) failed.\n",port); close(sock); return -1;}return sock;
}// 把代理路由參數(shù)加載到vroute容器。
bool loadroute(const char *inifile)
{cifile ifile;if (ifile.open(inifile)==false){logfile.write("打開代理路由參數(shù)文件(%s)失敗。\n",inifile); return false;}string strbuffer;ccmdstr cmdstr;while (true){if (ifile.readline(strbuffer)==false) break;// 刪除說明文字,#后面的部分。auto pos=strbuffer.find("#");if (pos!=string::npos) strbuffer.resize(pos);replacestr(strbuffer,"  "," ",true);    // 把兩個空格替換成一個空格,注意第四個參數(shù)。deletelrchr(strbuffer,' ');                 // 刪除兩邊的空格。// 拆分參數(shù)。cmdstr.splittocmd(strbuffer," ");if (cmdstr.size()!=3) continue;memset(&stroute,0,sizeof(struct st_route));cmdstr.getvalue(0,stroute.srcport);          // 源端口。cmdstr.getvalue(1,stroute.dstip);             // 目標地址。cmdstr.getvalue(2,stroute.dstport);         // 目標端口。vroute.push_back(stroute);}return true;
}void EXIT(int sig)
{logfile.write("程序退出,sig=%d。\n\n",sig);// 關(guān)閉監(jiān)聽內(nèi)網(wǎng)程序的socket。close(cmdlistensock);// 關(guān)閉內(nèi)網(wǎng)程序與服務端的命令通道。close(cmdconnsock);// 關(guān)閉全部監(jiān)聽的socket。for (auto &aa:vroute)if (aa.listensock>0) close(aa.listensock);// 關(guān)閉全部客戶端的socket。for (auto aa:clientsocks)if (aa>0) close(aa);close(epollfd);   // 關(guān)閉epoll。close(tfd);       // 關(guān)閉定時器。exit(0);
}

rinetdin.cpp代碼:

/** 程序名:rinetdin.cpp,反向網(wǎng)絡(luò)代理服務程序-內(nèi)網(wǎng)端。* 作者:張咸武
*/
#include "_public.h"
using namespace idc;int  cmdconnsock;  // 內(nèi)網(wǎng)程序與外網(wǎng)程序的命令通道的socket。int epollfd=0;     // epoll的句柄。
int tfd=0;            // 定時器的句柄。#define MAXSOCK  1024
int clientsocks[MAXSOCK];       // 存放每個socket連接對端的socket的值。
int clientatime[MAXSOCK];       // 存放每個socket連接最后一次收發(fā)報文的時間。
string clientbuffer[MAXSOCK]; // 存放每個socket發(fā)送內(nèi)容的buffer。// 向目標ip和端口發(fā)起socket連接,bio取值:false-非阻塞io,true-阻塞io。
int conntodst(const char *ip,const int port,bool bio=false);void EXIT(int sig);   // 進程退出函數(shù)。clogfile logfile;// cpactive pactive;     // 進程心跳。int main(int argc,char *argv[])
{if (argc != 4){printf("\n");printf("Using :./rinetdin logfile ip port\n\n");printf("Sample:./rinetdin /tmp/rinetdin.log 192.168.192.136 5001\n\n");printf("        /project/tools/bin/procctl 5 /project/tools/bin/rinetdin /tmp/rinetdin.log 192.168.150.128 5001\n\n");printf("logfile 本程序運行的日志文件名。\n");printf("ip      外網(wǎng)代理程序的ip地址。\n");printf("port    外網(wǎng)代理程序的通訊端口。\n\n\n");return -1;}// 關(guān)閉全部的信號和輸入輸出。// 設(shè)置信號,在shell狀態(tài)下可用 "kill + 進程號" 正常終止些進程。// 但請不要用 "kill -9 +進程號" 強行終止。closeioandsignal(); signal(SIGINT,EXIT); signal(SIGTERM,EXIT);// 打開日志文件。if (logfile.open(argv[1])==false){printf("打開日志文件失敗(%s)。\n",argv[1]); return -1;}// pactive.addpInfo(30,"inetd");       // 設(shè)置進程的心跳超時間為30秒。// 建立與外網(wǎng)程序的命令通道,采用阻塞的socket。if ((cmdconnsock=conntodst(argv[2],atoi(argv[3]),true))<0){logfile.write("tcpclient.connect(%s,%s) 失敗。\n",argv[2],argv[3]); return -1;}logfile.write("與外部的命令通道已建立(cmdconnsock=%d)。\n",cmdconnsock);// 命令通道建立之后,再設(shè)置為非阻塞的。fcntl(cmdconnsock,F_SETFL,fcntl(cmdconnsock,F_GETFD,0)|O_NONBLOCK);// 創(chuàng)建epoll句柄。epollfd=epoll_create(1);struct epoll_event ev;  // 聲明事件的數(shù)據(jù)結(jié)構(gòu)。// 為命令通道的socket準備可讀事件。ev.events=EPOLLIN;ev.data.fd=cmdconnsock;epoll_ctl(epollfd,EPOLL_CTL_ADD,cmdconnsock,&ev);// 創(chuàng)建定時器。tfd=timerfd_create(CLOCK_MONOTONIC,TFD_NONBLOCK|TFD_CLOEXEC);  // 創(chuàng)建timerfd。struct itimerspec timeout;memset(&timeout,0,sizeof(struct itimerspec));timeout.it_value.tv_sec = 20;           // 超時時間為20秒。timeout.it_value.tv_nsec = 0;timerfd_settime(tfd,0,&timeout,0);  // 開始計時。// 為定時器準備事件。ev.events=EPOLLIN;               ev.data.fd=tfd;epoll_ctl(epollfd,EPOLL_CTL_ADD,tfd,&ev);       // 把定時器的讀事件加入epollfd中。// pactive.addpinfo(30,"rinetdin");   // 設(shè)置進程的心跳超時間為30秒。struct epoll_event evs[10];      // 存放epoll返回的事件。while (true){// 等待監(jiān)視的socket有事件發(fā)生。int infds=epoll_wait(epollfd,evs,10,-1);// 返回失敗。if (infds < 0) { logfile.write("epoll() failed。\n"); EXIT(-1); }// 遍歷epoll返回的已發(fā)生事件的數(shù)組evs。for (int ii=0;ii<infds;ii++){// 如果定時器的時間已到,有兩件事要做:1)設(shè)置進程的心跳;2)清理空閑的客戶端socket。if (evs[ii].data.fd==tfd){// logfile.write("定時器時間已到。\n");timerfd_settime(tfd,0,&timeout,NULL);  // 重新開始計時。// pactive.uptatime();        // 1)更新進程心跳。// 2)清理空閑的客戶端socket。for (int jj=0;jj<MAXSOCK;jj++){// 如果客戶端socket空閑的時間超過80秒就關(guān)掉它。if ( (clientsocks[jj]>0) && ((time(0)-clientatime[jj])>80) ){logfile.write("client(%d,%d) timeout。\n",clientsocks[jj],clientsocks[clientsocks[jj]]);close(clientsocks[jj]);  close(clientsocks[clientsocks[jj]]);clientsocks[clientsocks[jj]]=0;     // 把數(shù)組中對端的socket置空,這一行代碼和下一行代碼的順序不能亂。clientsocks[jj]=0;                         // 把數(shù)組中本端的socket置空,這一行代碼和上一行代碼的順序不能亂。}}continue;}// 如果發(fā)生事件的是命令通道。if (evs[ii].data.fd==cmdconnsock){// 讀取命令通道socket報文內(nèi)容。char buffer[256];memset(buffer,0,sizeof(buffer));if (recv(cmdconnsock,buffer,sizeof(buffer),0)<=0){logfile.write("與外網(wǎng)的命令通道已斷開。\n"); EXIT(-1);}// 如果收到的是心跳報文。if (strcmp(buffer,"<activetest>")==0) continue;// 如果收到的是新建連接的命令。// 向外網(wǎng)服務端發(fā)起連接請求。int srcsock=conntodst(argv[2],atoi(argv[3]));if (srcsock<0) continue;if (srcsock>=MAXSOCK){logfile.write("連接數(shù)已超過最大值%d。\n",MAXSOCK); close(srcsock); continue;}// 從命令報文內(nèi)容中獲取目標服務器的地址和端口。char dstip[11];int  dstport;getxmlbuffer(buffer,"dstip",dstip,30);getxmlbuffer(buffer,"dstport",dstport);// 向目標服務器的地址和端口發(fā)起socket連接。int dstsock=conntodst(dstip,dstport);if (dstsock<0) { close(srcsock); continue; }if (dstsock>=MAXSOCK){ logfile.write("連接數(shù)已超過最大值%d。\n",MAXSOCK); close(srcsock); close(dstsock); continue;} // 把內(nèi)網(wǎng)和外網(wǎng)的socket對接在一起。logfile.write("新建內(nèi)外網(wǎng)通道(%d,%d) ok。\n",srcsock,dstsock);// 為新連接的兩個socket準備可讀事件,并添加到epoll中。ev.data.fd=srcsock; ev.events=EPOLLIN;epoll_ctl(epollfd,EPOLL_CTL_ADD,srcsock,&ev);ev.data.fd=dstsock; ev.events=EPOLLIN;epoll_ctl(epollfd,EPOLL_CTL_ADD,dstsock,&ev);// 更新clientsocks數(shù)組中兩端soccket的值和活動時間。clientsocks[srcsock]=dstsock; clientsocks[dstsock]=srcsock;clientatime[srcsock]=time(0); clientatime[dstsock]=time(0);continue;}// 如果是客戶端連接的socke有事件,分三種情況:1)客戶端有報文發(fā)過來;2)客戶端連接已斷開;3)有數(shù)據(jù)要發(fā)給客戶端。// 如果從通道一端的socket讀取到了數(shù)據(jù),把數(shù)據(jù)存放在對端socket的緩沖區(qū)中。//  if (evs[ii].events==EPOLLIN)   // 不要這么寫,有讀事件是1,有寫事件是4,如果讀和寫都有,是5。if (evs[ii].events&EPOLLIN)     // 判斷是否為讀事件。 {char buffer[5000];     // 存放從接收緩沖區(qū)中讀取的數(shù)據(jù)。int    buflen=0;          // 從接收緩沖區(qū)中讀取的數(shù)據(jù)的大小。// 從通道的一端讀取數(shù)據(jù)。if ( (buflen=recv(evs[ii].data.fd,buffer,sizeof(buffer),0)) <= 0 ){// 如果連接已斷開,需要關(guān)閉通道兩端的socket。logfile.write("client(%d,%d) disconnected。\n",evs[ii].data.fd,clientsocks[evs[ii].data.fd]);close(evs[ii].data.fd);                                         // 關(guān)閉客戶端的連接。close(clientsocks[evs[ii].data.fd]);                     // 關(guān)閉客戶端對端的連接。clientsocks[clientsocks[evs[ii].data.fd]]=0;       // 把數(shù)組中對端的socket置空,這一行代碼和下一行代碼的順序不能亂。clientsocks[evs[ii].data.fd]=0;                           // 把數(shù)組中本端的socket置空,這一行代碼和上一行代碼的順序不能亂。continue;}// 成功的讀取到了數(shù)據(jù),把接收到的報文內(nèi)容原封不動的發(fā)給通道的對端。// logfile.write("from %d to %d,%d bytes。\n",evs[ii].data.fd,clientsocks[evs[ii].data.fd],buflen);// send(clientsocks[evs[ii].data.fd],buffer,buflen,0);logfile.write("from %d,%d bytes\n",evs[ii].data.fd,buflen);// 把讀取到的數(shù)據(jù)追加到對端socket的buffer中。clientbuffer[clientsocks[evs[ii].data.fd]].append(buffer,buflen);// 修改對端socket的事件,增加寫事件。ev.data.fd=clientsocks[evs[ii].data.fd];ev.events=EPOLLIN|EPOLLOUT;epoll_ctl(epollfd,EPOLL_CTL_MOD,ev.data.fd,&ev);// 更新通道兩端socket的活動時間。clientatime[evs[ii].data.fd]=time(0); clientatime[clientsocks[evs[ii].data.fd]]=time(0);  }// 判斷客戶端的socket是否有寫事件(發(fā)送緩沖區(qū)沒有滿)。if (evs[ii].events&EPOLLOUT){// 把socket緩沖區(qū)中的數(shù)據(jù)發(fā)送出去。int writen=send(evs[ii].data.fd,clientbuffer[evs[ii].data.fd].data(),clientbuffer[evs[ii].data.fd].length(),0);// 以下代碼模擬不能一次發(fā)完全部數(shù)據(jù)的場景。//int ilen;//if (clientbuffer[evs[ii].data.fd].length()>10) ilen=10;//else ilen=clientbuffer[evs[ii].data.fd].length();//int writen=send(evs[ii].data.fd,clientbuffer[evs[ii].data.fd].data(),ilen,0);logfile.write("to %d,%d bytes\n",evs[ii].data.fd,writen);// 刪除socket緩沖區(qū)中已成功發(fā)送的數(shù)據(jù)。clientbuffer[evs[ii].data.fd].erase(0,writen);// 如果socket緩沖區(qū)中沒有數(shù)據(jù)了,不再關(guān)心socket的寫件事。if (clientbuffer[evs[ii].data.fd].length()==0){ev.data.fd=evs[ii].data.fd;ev.events=EPOLLIN;epoll_ctl(epollfd,EPOLL_CTL_MOD,ev.data.fd,&ev);}}}}return 0;
}// 向目標地址和端口發(fā)起socket連接。
int conntodst(const char *ip,const int port,bool bio)
{// 第1步:創(chuàng)建客戶端的socket。int sockfd;if ( (sockfd = socket(AF_INET,SOCK_STREAM,0))==-1) return -1; // 第2步:向服務器發(fā)起連接請求。struct hostent* h;if ( (h = gethostbyname(ip)) == 0 ) { close(sockfd); return -1; }struct sockaddr_in servaddr;memset(&servaddr,0,sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(port); // 指定服務端的通訊端口。memcpy(&servaddr.sin_addr,h->h_addr,h->h_length);// 把socket設(shè)置為非阻塞。if (bio==false) fcntl(sockfd,F_SETFL,fcntl(sockfd,F_GETFD,0)|O_NONBLOCK);if (connect(sockfd, (struct sockaddr *)&servaddr,sizeof(servaddr))<0){if (errno!=EINPROGRESS){logfile.write("connect(%s,%d) failed.\n",ip,port); return -1;}}return sockfd;
}void EXIT(int sig)
{logfile.write("程序退出,sig=%d。\n\n",sig);// 關(guān)閉內(nèi)網(wǎng)程序與外網(wǎng)程序的命令通道。close(cmdconnsock);// 關(guān)閉全部客戶端的socket。for (auto aa:clientsocks)if (aa>0) close(aa);close(epollfd);   // 關(guān)閉epoll。close(tfd);       // 關(guān)閉定時器。exit(0);
}
http://www.risenshineclean.com/news/27584.html

相關(guān)文章:

  • wordpress 8211如何優(yōu)化網(wǎng)絡(luò)速度
  • 部門網(wǎng)站建設(shè)存在的問題優(yōu)化大師免費版下載
  • 做論壇網(wǎng)站的cms網(wǎng)絡(luò)廣告策劃方案
  • 西安做網(wǎng)站的seo三人行論壇
  • 11號在線 網(wǎng)站開發(fā)廣州seo推薦
  • 沒有備案的網(wǎng)站可以用ip訪問嗎智能營銷方法
  • 海淀視頻網(wǎng)站建設(shè)搜索引擎調(diào)詞工具哪個好
  • 杭州電子商務公司排行seo推廣外包報價表
  • 做網(wǎng)站公司在哪電子商務沙盤seo關(guān)鍵詞
  • 設(shè)計網(wǎng)站賣錢企業(yè)網(wǎng)站模板源碼
  • 邯鄲網(wǎng)站制作找誰衡陽seo優(yōu)化報價
  • 怎么做網(wǎng)站推銷產(chǎn)品58同城安居客
  • 修改WordPress網(wǎng)站中國萬網(wǎng)域名注冊免費
  • 平面設(shè)計圖網(wǎng)站線下推廣方式
  • 阿里云官方網(wǎng)站百度關(guān)鍵詞規(guī)劃師入口
  • 免費交友網(wǎng)站模板精準信息300099
  • 織夢禁止網(wǎng)站右擊網(wǎng)站推廣
  • 做網(wǎng)站賺錢難網(wǎng)站制作流程是什么
  • 杭州建站價格成功品牌策劃案例
  • 手機網(wǎng)站建設(shè)開發(fā)搜索引擎大全網(wǎng)址
  • 簡單的企業(yè)小網(wǎng)站網(wǎng)站設(shè)計制作一條龍
  • 武漢做網(wǎng)站報價山西網(wǎng)絡(luò)推廣
  • 衢州網(wǎng)站建設(shè)費用教育機構(gòu)培訓
  • 我的網(wǎng)站首頁打不開b站2023年免費入口
  • 住房和城鄉(xiāng)建設(shè)部網(wǎng)站報名瀏覽器打開
  • 新鄉(xiāng)住房與城鄉(xiāng)建設(shè)廳網(wǎng)站網(wǎng)站推廣營銷
  • 智聯(lián)招聘網(wǎng)站怎么做兩份簡歷360優(yōu)化大師軟件
  • 做啥英文網(wǎng)站賺錢互聯(lián)網(wǎng)公司網(wǎng)站模板
  • 電子商務網(wǎng)站建設(shè)實訓展示流量網(wǎng)站
  • 臺州網(wǎng)站建設(shè)方案優(yōu)化廣告設(shè)計