在C:代理服务器的HTTP请求到另一台服务器 [英] In C: Proxy HTTP requests to another server

查看:109
本文介绍了在C:代理服务器的HTTP请求到另一台服务器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图将HTTP请求代理到其他HTTP服务器。上游HTTP服务器的主机名和端口号,分别是server_proxy_hostname和server_proxy_port。

第一步是做server_proxy_hostname的DNS查询。

其次,我创建了一个网络套接字,并选择Connet我从DNS获得的IP地址。

最后一步:等待两个插座上的新数据。当数据到达时,我立即读给一个缓冲器,然后将其写入到其它
插座。这保持了HTTP客户端和之间的双向通信
上游HTTP服务器。

如果有任何插座关闭后,我关闭另外一个。


现在的问题是,它不工作。 (超时)

我相信,我得到我的IP地址的方式是正确的,所以这个问题必须在任我while循环(它永远不会终止?),或者我叫连接部分()。我尝试添加用于读取(错误终止),选择(),但也不能工作。

 无效handle_proxy_request(INT FD){  字符* targetHostName = server_proxy_hostname;
  INT TARGETPORT = server_proxy_port;
  结构hostent *信息;
  信息=的gethostbyname(targetHostName);
  struct in_addr,这个** ipAddresslist;
  ipAddresslist =(struct in_addr,这个**)(信息 - > h_addr_list);
  struct in_addr,这个* ip地址= ipAddresslist [0];
  的printf(IP地址为%s \\ n,INET_NTOA(* ip地址));  / * IP为in_addr等结构* /
  无符号长IP = inet_addr(INET_NTOA(* ip地址));
  struct in_addr,这个addressIp = {}知识产权;
  结构SOCKADDR_IN地址= {PF_INET,htons(TARGETPORT),addressIp};  INT socket_num =插座(PF_INET,SOCK_STREAM,0);
  连接(socket_num,(结构sockaddr *)及地址的sizeof(地址));  / *为select()的部分* /
  焦炭BUF [10000]
  INT NFDs的=(FD> socket_num)FD:socket_num;
  FD_SET读集;
  FD_SET写集;  而(1){    FD_ZERO(安培;读集);
    FD_ZERO(安培;写集);
    FD_SET(FD,&安培;读集);
    FD_SET(socket_num,&安培;读集);
    FD_SET(FD,&安培;写集);
    FD_SET(socket_num,&安培;写集);
    INT selectReturn =选择(NFDs的,和放大器;读集,和放大器;写集,NULL,NULL);
    如果(selectReturn == -1){
      打破;
    }
    如果(FD_ISSET(FD,&安培;读集)){
      INT readStat =读(FD,BUF,sizeof的(BUF));
      INT状态=写(socket_num,BUF,sizeof的(BUF));
      如果(状态== -1 || readStat == -1){
        关闭(socket_num);
        关闭(FD);
        打破;
      }
      / * memset的(BUF,0,sizeof的(BUF)); * /
    }
    如果(FD_ISSET(socket_num,&安培;读集)){
      INT readStat2 =读(socket_num,BUF,sizeof的(BUF));
      INT STATUS2 =写(FD,BUF,sizeof的(BUF));
      如果(状态== -1 || readStat2 == -1){
        关闭(socket_num);
        关闭(FD);
        打破;
      }
    }  }}


解决方案

  INT socket_num =插座(PF_INET,SOCK_STREAM,0);

未选中。勾选此错误。

 连接(socket_num,(结构sockaddr *)及地址的sizeof(地址));

同上。

  FD_SET(FD,&安培;写集);
FD_SET(socket_num,&安培;写集);

删除。这是不良的做法。套接字是几乎总是准备好写的,所以你不应该使用写集除非你有previously遇到一种情况,即插座还没有准备好写,即的write()返回 1 的errno == EAGAIN / EWOULDBLOCK。

  INT readStat =读(FD,BUF,sizeof的(BUF));
INT状态=写(socket_num,BUF,sizeof的(BUF));

这应该是

  INT状态=写(socket_num,BUF,readStat);

在这两种情况下,插座

和它应该是的 preceded 的通过测试 readStat == 0 ,说明流的末尾,而 readStat == -1 ,指示错误,你应该跟踪。

您不能在此code得到一个超时,因为你还没有设置任何

有皱纹。如果你流的末尾读取插座,你应该关闭其他插座输出。如果你流的末尾套接字上你已经关闭输出,关闭它们。这种传播正确的在正确的时间两个方向的鳍。

当您从任何系统调用得到任何错误,必须的立即的通话 PERROR()或结果<$ C $其记录C>字符串错误(),调用任何其他系统调用之前。

I'm trying to proxy HTTP requests to another HTTP server. The hostname and port number of the upstream HTTP server, respectively, are server_proxy_hostname and server_proxy_port.

The first step is to do a DNS lookup of the server_proxy_hostname.

Secondly, I create a network socket and connet it to the IP address I got from DNS.

Last step: Wait for new data on both sockets. When data arrives, I immediately read it to a buffer and then write it to the other socket. This maintains a 2-way communication between the HTTP client and the upstream HTTP server.

If any of the socket is closed, I close the other one.


The problem right now is that it is not working. (It times out)

I believe that the way I'm getting my IP addresses is correct, so the problem has to be in either my while loop (it never terminates?) or the part where I called connect(). I tried adding error termination for read() and select() but that didn't work either.

void handle_proxy_request(int fd) {

  char * targetHostName = server_proxy_hostname;
  int targetPort = server_proxy_port;
  struct hostent *info;
  info = gethostbyname(targetHostName);
  struct in_addr ** ipAddresslist;
  ipAddresslist = (struct in_addr **) (info -> h_addr_list);
  struct in_addr * ipAddress = ipAddresslist[0];
  printf("ip address is %s\n", inet_ntoa(*ipAddress));

  /*ip for in_addr struct*/
  unsigned long ip = inet_addr(inet_ntoa(*ipAddress));
  struct in_addr addressIp = {ip};
  struct sockaddr_in address = {PF_INET, htons(targetPort), addressIp};

  int socket_num = socket(PF_INET, SOCK_STREAM, 0);
  connect(socket_num, (struct sockaddr *)&address, sizeof(address));

  /*portion for select()*/
  char buf[10000];
  int nfds = (fd > socket_num)?fd:socket_num;
  fd_set readSet;
  fd_set writeSet;

  while (1) {

    FD_ZERO(&readSet);
    FD_ZERO(&writeSet);
    FD_SET(fd, &readSet);
    FD_SET(socket_num, &readSet);
    FD_SET(fd, &writeSet);
    FD_SET(socket_num, &writeSet);
    int selectReturn = select(nfds, &readSet, &writeSet, NULL, NULL);
    if (selectReturn == -1){
      break;
    }
    if(FD_ISSET(fd, &readSet)){
      int readStat = read(fd, buf, sizeof(buf));
      int status = write(socket_num, buf, sizeof(buf));
      if (status == -1 || readStat == -1){
        close(socket_num);
        close(fd);
        break;
      }
      /*memset(buf, 0, sizeof(buf));*/
    }
    if(FD_ISSET(socket_num, &readSet)){
      int readStat2 = read(socket_num, buf, sizeof(buf));
      int status2 = write(fd, buf, sizeof(buf));
      if (status2 == -1 || readStat2 == -1){
        close(socket_num);
        close(fd);
        break;
      }
    }

  }

}

解决方案

int socket_num = socket(PF_INET, SOCK_STREAM, 0);

Unchecked. Check this for errors.

connect(socket_num, (struct sockaddr *)&address, sizeof(address));

Ditto.

FD_SET(fd, &writeSet);
FD_SET(socket_num, &writeSet);

Remove. This is poor practice. Sockets are almost always ready to write, so you shouldn't use the writeSet unless you have previously encountered a case where a socket wasn't ready to write, i.e. write() returned -1 with errno == EAGAIN/EWOULDBLOCK.

int readStat = read(fd, buf, sizeof(buf));
int status = write(socket_num, buf, sizeof(buf));

That should be

int status = write(socket_num, buf, readStat);

in both socket cases.

and it should be preceded by tests for readStat == 0, indicating end of stream, and readStat == -1, indicating an error, which you should trace.

You can't get a timeout in this code, as you haven't set any.

There's a wrinkle. If you get end of stream reading a socket you should shutdown the other socket for output. If you get end of stream on a socket you've already shutdown for output, close them both. This correctly propagates FINs in both directions at the correct times.

When you get any error from any system call, you must immediately call perror() or log it with the result strerror(), before you call any other system calls.

这篇关于在C:代理服务器的HTTP请求到另一台服务器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆