当前位置: 首页 > news >正文

软文网站外包外贸推广系统

软文网站外包,外贸推广系统,青海建筑人才网,热 综合-网站正在建设中1 概念 1.1 反向代理概念 反向代理是指以代理服务器来接收客户端的请求#xff0c;然后将请求转发给内部网络上的服务器#xff0c;将从服务器上得到的结果返回给客户端#xff0c;此时代理服务器对外表现为一个反向代理服务器。 对于客户端来说#xff0c;反向代理就相当于…  1 概念 1.1 反向代理概念 反向代理是指以代理服务器来接收客户端的请求然后将请求转发给内部网络上的服务器将从服务器上得到的结果返回给客户端此时代理服务器对外表现为一个反向代理服务器。 对于客户端来说反向代理就相当于目标服务器只需要将反向代理当作目标服务器一样发送请求就可以了并且客户端不需要进行任何设置。 1.2 特点 反向代理是代理服务器为服务器收发请求使真实服务器对客户端不可见。 原文链接https://blog.csdn.net/Dax1_/article/details/124652162 1.3 反向代理场景 正向代理A可以访问BB可以访问C。如果A要访问C那么要在B上面部署正向代理模块。 反向代理A可以访问BC可以访问BB不能访问A和C如果A要访问C可以用反向代理。 完整的反向代理图如下所示 不适用代理的情况下外网不能访问企业内网的服务器如果希望访问企业内网必须要使用反向代理如果要使用反向代理企业必须要有一个公网的服务器公网的IP。 正向代理只有一个模块一个服务程序而反向代理有两个模块两个服务程序外网模块和内网模块。 2 反向代理实现 2.1 反向代理基本思路 服务程序启动的时候内网模块向外网模块发起一个TCP连接建立一条传输通道称为命令通道 之后外网模块读取路由参数配置文件外网模块需要监听512251235128三个端口 用户1连接了外网服务器的5122端口外网模块通过命令通道告诉内网模块帮我连192.168.168.1.4的22端口 内网模块向外网模块发起TCP连接建立一条传输通道同时内网模块连接192.168.1.4 22整个链路就建立起来了。 外网模块外网程序 外网模块没有主动的向任何服务器发起连接。外网程序没有为命令通道的socket准备epoll事件因为命令通道不需要监听只有外网程序向内网发送命令内网程序并不会向外网程序发送命令。。 内网模块内网程序 内网程序非阻塞socket命令通道建立之后再设置为非阻塞的加入epoll事件。此时内网模块与外网模块都进入事件循环外网程序监听着路由配置文件的端口可以开始接受用户客户端的连接请求了内网程序epoll中只有命令通道的socket内网程序也做好了准备接收外网程序的命令。 2.2 框架流程图 2.3 反向代理框架实现 rinetd.cpp外网模块 /** 程序名rinetd.cpp反向网络代理服务程序-外网端。* 作者张咸武 */ #include _public.h using namespace idc;// 代理路由参数的结构体。 struct st_route {int srcport; // 源端口。char dstip[31]; // 目标主机的地址。int dstport; // 目标主机的端口。int listensock; // 监听源端口的socket。 }stroute; vectorstruct st_route vroute; // 代理路由的容器。 bool loadroute(const char *inifile); // 把代理路由参数加载到vroute容器。int initserver(int port); // 初始化服务端的监听端口。int epollfd0; // epoll的句柄。 int tfd0; // 定时器的句柄。#define MAXSOCK 1024 int clientsocks[MAXSOCK]; // 存放每个socket连接对端的socket的值。 int clientatime[MAXSOCK]; // 存放每个socket连接最后一次收发报文的时间。 string clientbuffer[MAXSOCK]; // 存放每个socket发送内容的buffer。int cmdlistensock0; // 命令通道监听的socket。 int cmdconnsock0; // 命令通道连接的socket。void EXIT(int sig); // 进程退出函数。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 代理路由参数配置文件。\n);printf(cmdport 与内网代理程序的通讯端口。\n\n);return -1;}// 关闭全部的信号和输入输出。// 设置信号,在shell状态下可用 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); // 设置进程的心跳超时间为30秒。// 把代理路由参数加载到vroute容器。if (loadroute(argv[2])false) return -1;logfile.write(加载代理路由参数成功(%d)。\n,vroute.size());// 初始化命令通道的监听端口。if ( (cmdlistensockinitserver(atoi(argv[3]))) 0 ){ logfile.write(initserver(%s) failed.\n,argv[3]); EXIT(-1);}// 等待内网程序的连接请求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(与内部的命令通道已建立(cmdconnsock%d)。\n,cmdconnsock);// 初始化服务端用于监听外网的socket。for (int ii0;iivroute.size();ii){if ( (vroute[ii].listensockinitserver(vroute[ii].srcport)) 0 ){logfile.write(initserver(%d) failed.\n,vroute[ii].srcport); EXIT(-1);}// 把监听socket设置成非阻塞。fcntl(vroute[ii].listensock,F_SETFL,fcntl(vroute[ii].listensock,F_GETFD,0)|O_NONBLOCK);}// 创建epoll句柄。epollfdepoll_create(1);struct epoll_event ev; // 声明事件的数据结构。// 为监听外网的socket准备可读事件。for (int ii0;iivroute.size();ii){ev.eventsEPOLLIN; // 读事件。ev.data.fdvroute[ii].listensock; epoll_ctl(epollfd,EPOLL_CTL_ADD,vroute[ii].listensock,ev); // 把监听外网的socket的读事件加入epollfd中。}// 创建定时器。tfdtimerfd_create(CLOCK_MONOTONIC,TFD_NONBLOCK|TFD_CLOEXEC); // 创建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.eventsEPOLLIN; ev.data.fdtfd;epoll_ctl(epollfd,EPOLL_CTL_ADD,tfd,ev); // 把定时器的读事件加入epollfd中。struct epoll_event evs[10]; // 存放epoll返回的事件。while (true){// 等待监视的socket有事件发生。int infdsepoll_wait(epollfd,evs,10,-1);// 返回失败。if (infds 0) { logfile.write(epoll() failed。); EXIT(-1); }// 遍历epoll返回的已发生事件的数组evs。for (int ii0;iiinfds;ii){// 如果定时器的时间已到有三件事要做1更新进程的心跳2向命令通道发送心跳报文3清理空闲的客户端socket。if (evs[ii].data.fdtfd){// logfile.write(定时器时间已到。\n);timerfd_settime(tfd,0,timeout,0); // 重新开始计时。// pactive.uptatime(); // 1更新进程心跳// 2向命令通道发送心跳报文char buffer[256];strcpy(buffer,activetest);if (send(cmdconnsock,buffer,strlen(buffer),0)0){logfile.write(与内网程序的命令通道已断开。\n); EXIT(-1);}// 3清理空闲的客户端socket。for (int jj0;jjMAXSOCK;jj){// 如果客户端socket空闲的时间超过80秒就关掉它。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]]);// 把数组中对端的socket置空这一行代码和下一行代码的顺序不能乱。clientsocks[clientsocks[jj]]0;// 把数组中本端的socket置空这一行代码和上一行代码的顺序不能乱。clientsocks[jj]0;}}continue;}// 如果发生事件的是监听的listensock表示外网有新的客户端连上来。int jj0;for (jj0;jjvroute.size();jj){if (evs[ii].data.fdvroute[jj].listensock){// 从已连接队列中获取一个已准备好的外网客户端的socket。struct sockaddr_in client;socklen_t len sizeof(client);int srcsock accept(vroute[jj].listensock,(struct sockaddr*)client,len);if (srcsock0) break;if (srcsockMAXSOCK) {logfile.write(连接数已超过最大值%d。\n,MAXSOCK); close(srcsock); break;}// 通过命令通道向内网程序发送命令把路由参数传给它。char buffer[256];memset(buffer,0,sizeof(buffer));sprintf(buffer,dstip%s/dstipdstport%d/dstport,vroute[jj].dstip,vroute[jj].dstport);if (send(cmdconnsock,buffer,strlen(buffer),0)0){logfile.write(与内网的命令通道已断开。\n); EXIT(-1);}// 接受内网程序的连接这里的accept()是阻塞的。int dstsockaccept(cmdlistensock,(struct sockaddr*)client,len);if (dstsock0) { close(srcsock); break; }if (dstsockMAXSOCK){logfile.write(连接数已超过最大值%d。\n,MAXSOCK); close(srcsock); close(dstsock); break;}// 把内网和外网客户端的socket对接在一起。// 为新连接的两个socket准备可读事件并添加到epoll中。ev.data.fdsrcsock; ev.eventsEPOLLIN;epoll_ctl(epollfd,EPOLL_CTL_ADD,srcsock,ev);ev.data.fddstsock; ev.eventsEPOLLIN;epoll_ctl(epollfd,EPOLL_CTL_ADD,dstsock,ev);// 更新clientsocks数组中两端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;}}// 如果jjvroute.size()表示事件在上面的for循环中已被处理。if (jjvroute.size()) continue;// 如果是客户端连接的socke有事件分三种情况1客户端有报文发过来2客户端连接已断开3有数据要发给客户端。// 如果从通道一端的socket读取到了数据把数据存放在对端socket的缓冲区中。// if (evs[ii].eventsEPOLLIN) // 不要这么写有读事件是1有写事件是4如果读和写都有是5。if (evs[ii].eventsEPOLLIN) // 判断是否为读事件。 {char buffer[5000]; // 存放从接收缓冲区中读取的数据。int buflen0; // 从接收缓冲区中读取的数据的大小。// 从通道的一端读取数据。if ( (buflenrecv(evs[ii].data.fd,buffer,sizeof(buffer),0)) 0 ){// 如果连接已断开需要关闭通道两端的socket。logfile.write(client(%d,%d) disconnected。\n,evs[ii].data.fd,clientsocks[evs[ii].data.fd]);close(evs[ii].data.fd); // 关闭客户端的连接。close(clientsocks[evs[ii].data.fd]); // 关闭客户端对端的连接。clientsocks[clientsocks[evs[ii].data.fd]]0; // 把数组中对端的socket置空这一行代码和下一行代码的顺序不能乱。clientsocks[evs[ii].data.fd]0; // 把数组中本端的socket置空这一行代码和上一行代码的顺序不能乱。continue;}// 成功的读取到了数据把接收到的报文内容原封不动的发给通道的对端。// 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);// 把读取到的数据追加到对端socket的buffer中。clientbuffer[clientsocks[evs[ii].data.fd]].append(buffer,buflen);// 修改对端socket的事件增加写事件。ev.data.fdclientsocks[evs[ii].data.fd];ev.eventsEPOLLIN|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是否有写事件发送缓冲区没有满。if (evs[ii].eventsEPOLLOUT){// 把socket缓冲区中的数据发送出去。int writensend(evs[ii].data.fd,clientbuffer[evs[ii].data.fd].data(),clientbuffer[evs[ii].data.fd].length(),0);// 以下代码模拟不能一次发完全部数据的场景。//int ilen;//if (clientbuffer[evs[ii].data.fd].length()10) ilen10;//else ilenclientbuffer[evs[ii].data.fd].length();//int writensend(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缓冲区中已成功发送的数据。clientbuffer[evs[ii].data.fd].erase(0,writen);// 如果socket缓冲区中没有数据了不再关心socket的写件事。if (clientbuffer[evs[ii].data.fd].length()0){ev.data.fdevs[ii].data.fd;ev.eventsEPOLLIN;epoll_ctl(epollfd,EPOLL_CTL_MOD,ev.data.fd,ev);}}}}return 0; }// 初始化服务端的监听端口。 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; }// 把代理路由参数加载到vroute容器。 bool loadroute(const char *inifile) {cifile ifile;if (ifile.open(inifile)false){logfile.write(打开代理路由参数文件(%s)失败。\n,inifile); return false;}string strbuffer;ccmdstr cmdstr;while (true){if (ifile.readline(strbuffer)false) break;// 删除说明文字#后面的部分。auto posstrbuffer.find(#);if (pos!string::npos) strbuffer.resize(pos);replacestr(strbuffer, , ,true); // 把两个空格替换成一个空格注意第四个参数。deletelrchr(strbuffer, ); // 删除两边的空格。// 拆分参数。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);// 关闭监听内网程序的socket。close(cmdlistensock);// 关闭内网程序与服务端的命令通道。close(cmdconnsock);// 关闭全部监听的socket。for (auto aa:vroute)if (aa.listensock0) close(aa.listensock);// 关闭全部客户端的socket。for (auto aa:clientsocks)if (aa0) close(aa);close(epollfd); // 关闭epoll。close(tfd); // 关闭定时器。exit(0); } rinetdin.cpp代码 /** 程序名rinetdin.cpp反向网络代理服务程序-内网端。* 作者张咸武 */ #include _public.h using namespace idc;int cmdconnsock; // 内网程序与外网程序的命令通道的socket。int epollfd0; // epoll的句柄。 int tfd0; // 定时器的句柄。#define MAXSOCK 1024 int clientsocks[MAXSOCK]; // 存放每个socket连接对端的socket的值。 int clientatime[MAXSOCK]; // 存放每个socket连接最后一次收发报文的时间。 string clientbuffer[MAXSOCK]; // 存放每个socket发送内容的buffer。// 向目标ip和端口发起socket连接bio取值false-非阻塞iotrue-阻塞io。 int conntodst(const char *ip,const int port,bool biofalse);void EXIT(int sig); // 进程退出函数。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 外网代理程序的ip地址。\n);printf(port 外网代理程序的通讯端口。\n\n\n);return -1;}// 关闭全部的信号和输入输出。// 设置信号,在shell状态下可用 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); // 设置进程的心跳超时间为30秒。// 建立与外网程序的命令通道采用阻塞的socket。if ((cmdconnsockconntodst(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);// 命令通道建立之后再设置为非阻塞的。fcntl(cmdconnsock,F_SETFL,fcntl(cmdconnsock,F_GETFD,0)|O_NONBLOCK);// 创建epoll句柄。epollfdepoll_create(1);struct epoll_event ev; // 声明事件的数据结构。// 为命令通道的socket准备可读事件。ev.eventsEPOLLIN;ev.data.fdcmdconnsock;epoll_ctl(epollfd,EPOLL_CTL_ADD,cmdconnsock,ev);// 创建定时器。tfdtimerfd_create(CLOCK_MONOTONIC,TFD_NONBLOCK|TFD_CLOEXEC); // 创建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.eventsEPOLLIN; ev.data.fdtfd;epoll_ctl(epollfd,EPOLL_CTL_ADD,tfd,ev); // 把定时器的读事件加入epollfd中。// pactive.addpinfo(30,rinetdin); // 设置进程的心跳超时间为30秒。struct epoll_event evs[10]; // 存放epoll返回的事件。while (true){// 等待监视的socket有事件发生。int infdsepoll_wait(epollfd,evs,10,-1);// 返回失败。if (infds 0) { logfile.write(epoll() failed。\n); EXIT(-1); }// 遍历epoll返回的已发生事件的数组evs。for (int ii0;iiinfds;ii){// 如果定时器的时间已到有两件事要做1设置进程的心跳2清理空闲的客户端socket。if (evs[ii].data.fdtfd){// logfile.write(定时器时间已到。\n);timerfd_settime(tfd,0,timeout,NULL); // 重新开始计时。// pactive.uptatime(); // 1更新进程心跳。// 2清理空闲的客户端socket。for (int jj0;jjMAXSOCK;jj){// 如果客户端socket空闲的时间超过80秒就关掉它。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; // 把数组中对端的socket置空这一行代码和下一行代码的顺序不能乱。clientsocks[jj]0; // 把数组中本端的socket置空这一行代码和上一行代码的顺序不能乱。}}continue;}// 如果发生事件的是命令通道。if (evs[ii].data.fdcmdconnsock){// 读取命令通道socket报文内容。char buffer[256];memset(buffer,0,sizeof(buffer));if (recv(cmdconnsock,buffer,sizeof(buffer),0)0){logfile.write(与外网的命令通道已断开。\n); EXIT(-1);}// 如果收到的是心跳报文。if (strcmp(buffer,activetest)0) continue;// 如果收到的是新建连接的命令。// 向外网服务端发起连接请求。int srcsockconntodst(argv[2],atoi(argv[3]));if (srcsock0) continue;if (srcsockMAXSOCK){logfile.write(连接数已超过最大值%d。\n,MAXSOCK); close(srcsock); continue;}// 从命令报文内容中获取目标服务器的地址和端口。char dstip[11];int dstport;getxmlbuffer(buffer,dstip,dstip,30);getxmlbuffer(buffer,dstport,dstport);// 向目标服务器的地址和端口发起socket连接。int dstsockconntodst(dstip,dstport);if (dstsock0) { close(srcsock); continue; }if (dstsockMAXSOCK){ logfile.write(连接数已超过最大值%d。\n,MAXSOCK); close(srcsock); close(dstsock); continue;} // 把内网和外网的socket对接在一起。logfile.write(新建内外网通道(%d,%d) ok。\n,srcsock,dstsock);// 为新连接的两个socket准备可读事件并添加到epoll中。ev.data.fdsrcsock; ev.eventsEPOLLIN;epoll_ctl(epollfd,EPOLL_CTL_ADD,srcsock,ev);ev.data.fddstsock; ev.eventsEPOLLIN;epoll_ctl(epollfd,EPOLL_CTL_ADD,dstsock,ev);// 更新clientsocks数组中两端soccket的值和活动时间。clientsocks[srcsock]dstsock; clientsocks[dstsock]srcsock;clientatime[srcsock]time(0); clientatime[dstsock]time(0);continue;}// 如果是客户端连接的socke有事件分三种情况1客户端有报文发过来2客户端连接已断开3有数据要发给客户端。// 如果从通道一端的socket读取到了数据把数据存放在对端socket的缓冲区中。// if (evs[ii].eventsEPOLLIN) // 不要这么写有读事件是1有写事件是4如果读和写都有是5。if (evs[ii].eventsEPOLLIN) // 判断是否为读事件。 {char buffer[5000]; // 存放从接收缓冲区中读取的数据。int buflen0; // 从接收缓冲区中读取的数据的大小。// 从通道的一端读取数据。if ( (buflenrecv(evs[ii].data.fd,buffer,sizeof(buffer),0)) 0 ){// 如果连接已断开需要关闭通道两端的socket。logfile.write(client(%d,%d) disconnected。\n,evs[ii].data.fd,clientsocks[evs[ii].data.fd]);close(evs[ii].data.fd); // 关闭客户端的连接。close(clientsocks[evs[ii].data.fd]); // 关闭客户端对端的连接。clientsocks[clientsocks[evs[ii].data.fd]]0; // 把数组中对端的socket置空这一行代码和下一行代码的顺序不能乱。clientsocks[evs[ii].data.fd]0; // 把数组中本端的socket置空这一行代码和上一行代码的顺序不能乱。continue;}// 成功的读取到了数据把接收到的报文内容原封不动的发给通道的对端。// 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);// 把读取到的数据追加到对端socket的buffer中。clientbuffer[clientsocks[evs[ii].data.fd]].append(buffer,buflen);// 修改对端socket的事件增加写事件。ev.data.fdclientsocks[evs[ii].data.fd];ev.eventsEPOLLIN|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是否有写事件发送缓冲区没有满。if (evs[ii].eventsEPOLLOUT){// 把socket缓冲区中的数据发送出去。int writensend(evs[ii].data.fd,clientbuffer[evs[ii].data.fd].data(),clientbuffer[evs[ii].data.fd].length(),0);// 以下代码模拟不能一次发完全部数据的场景。//int ilen;//if (clientbuffer[evs[ii].data.fd].length()10) ilen10;//else ilenclientbuffer[evs[ii].data.fd].length();//int writensend(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缓冲区中已成功发送的数据。clientbuffer[evs[ii].data.fd].erase(0,writen);// 如果socket缓冲区中没有数据了不再关心socket的写件事。if (clientbuffer[evs[ii].data.fd].length()0){ev.data.fdevs[ii].data.fd;ev.eventsEPOLLIN;epoll_ctl(epollfd,EPOLL_CTL_MOD,ev.data.fd,ev);}}}}return 0; }// 向目标地址和端口发起socket连接。 int conntodst(const char *ip,const int port,bool bio) {// 第1步创建客户端的socket。int sockfd;if ( (sockfd socket(AF_INET,SOCK_STREAM,0))-1) return -1; // 第2步向服务器发起连接请求。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设置为非阻塞。if (biofalse) 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);// 关闭内网程序与外网程序的命令通道。close(cmdconnsock);// 关闭全部客户端的socket。for (auto aa:clientsocks)if (aa0) close(aa);close(epollfd); // 关闭epoll。close(tfd); // 关闭定时器。exit(0); }
http://www.dnsts.com.cn/news/20837.html

相关文章:

  • 自建网站平台的页面功能网站空间 域名
  • 电脑手机网站制作万维定制平台
  • 苏州区建设局网站首页专门做相声的网站
  • 门户网站建设请示报告慈溪市网站开发
  • 做商城的网站程序正规网站建设公司多少钱
  • 手机网站智能管理系统河北省建设项目环保备案网站
  • 企业的品牌宣传策划seo快速排名培训
  • 江苏建筑网站建设wordpress导航不固定
  • 定制产品网站网站建设服务哪家
  • 做版权保护的网站国际域名网站
  • 长沙网站se0推广优化公司产品网站用什么软件做
  • 大众点评怎么做团购网站怎么制作图片和文字一起
  • 网站js聊天代码远程教育网站建设方案
  • 可以做任务挣钱的网站不是做有网站都叫狠狠
  • 做电影网站算侵权吗小程序界面设计模板
  • 网站开发如何共用菜单栏require刚做的网站怎么才能搜索到
  • 江苏省城乡建设厅网站湖人最新消息
  • 电商网站管理小型局域网组建方案
  • 做物流网站的公司哪家好租赁商城手机网站开发
  • tp5企业网站开发视频建筑业资质查询网站
  • 基于django电商网站开发课设报告网站做新浪图床
  • 做网站二级页面的关于自行建设门户网站的请示
  • 找it工作有什么好的招聘网站nginx wordpress 伪静态
  • 建设外贸国外站点网站电子商务专业有什么用
  • 电子商务的网站建设的可用性广州app开发外包
  • 内蒙古网站建站ui设计网站建设是什么
  • 百度不收录新网站php网站开发工具有哪些
  • 网站标题的优化如何选择编程培训机构
  • 免费wap网站推荐做视频网站 买带宽
  • 手机app下载网站带商城的企业网站源码