Avatar billede Slettet bruger
24. maj 2007 - 14:48 Der er 12 kommentarer og
1 løsning

Proxy server

Er det muligt at lave en proxy server i C++?

Den skal fungere sådan, at programmet lytter på port 80, videresender forespørgsler fra brugere til en udvalgt IP adresse, og returnerer resultatet til brugeren.

Jeg har allerede lavet en sådan proxy funktion i perl, men på trods af optimering og nedtrimning af koden klarer scriptet "kun" op til 300 hits/sek på en 3 ghz maskine.

I så fald, nogen som kan bidrage med en skabelon kode? Jeg har kun studeret C++ i en uges tid.
Avatar billede arne_v Ekspert
24. maj 2007 - 15:22 #1
Selvfoelgelig er det muligt. Man kan lave naesten alt i C++. Og mit gaet er at
stort set alle proxy servere er lavet i enten C eller C++.

Du skal have styr paa to ting:
- socket network IO
- multi threading

Jeg kan godt finde nogle kode eksempler, men umiddelbart synes jeg at det er en
voldsom opgave at starte paa med en uges erfaring.
Avatar billede Slettet bruger
24. maj 2007 - 15:42 #2
Well jeg er lærenem, og "mestrer" allerede en række sprog i forvejen. Så lad mig prøve :)

Jeg giver gerne point for de omtalte kodeeksempler.
Avatar billede arne_v Ekspert
24. maj 2007 - 15:54 #3
#include <iostream>

using namespace std;

#include <windows.h>

CRITICAL_SECTION cs;

DWORD __stdcall tfunc(void *p)
{
  int *arg = (int *)p;
  for(int i=0;i<10;i++)
  {
      EnterCriticalSection(&cs);
      cout << *arg << endl;
      LeaveCriticalSection(&cs);
      Sleep(1000);
  }
  return 0;
}

int main()
{
  InitializeCriticalSection(&cs); 
  int arg1 = 123;
  DWORD id1;
  HANDLE h1 = CreateThread(NULL,0,tfunc,&arg1,0,&id1);
  int arg2 = 456;
  DWORD id2;
  HANDLE h2 = CreateThread(NULL,0,tfunc,&arg2,0,&id2);
  WaitForSingleObject(h1,INFINITE);
  WaitForSingleObject(h2,INFINITE);
  return 0;
}
Avatar billede arne_v Ekspert
24. maj 2007 - 15:59 #4
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;

#include <windows.h>

const char *WELCOME="Welcome\r\n";
const char *QUIT="quit\r\n";
const char *BYEBYE="Bye bye\r\n";
const char *UNKNOWN="Unknown command\r\n";
const char *NEWLINE="\r\n";

DWORD __stdcall client(void *p)
{
    int sd2=*((int*)p);
    send(sd2,WELCOME,strlen(WELCOME),0);
    char buf[80];
    memset(buf,0x00,sizeof(buf));
    int ix=0;
    int len;
    while((len=recv(sd2,buf+ix,sizeof(buf)-ix,0))>0)
    {
        ix=ix+len;
        if(strstr(buf,NEWLINE)!=NULL)
        {
            char cmd[80];
            memset(cmd,0x00,sizeof(cmd));
            int cmdlen = (strstr(buf,NEWLINE)-buf)+strlen(NEWLINE);
            memmove(cmd,buf,cmdlen);
            memmove(buf,buf+cmdlen,ix-cmdlen);
            ix=ix-cmdlen;
            memset(buf+ix,0x00,sizeof(buf)-ix);
            if(strcmpi(cmd,QUIT)==0)
            {
                send(sd2,BYEBYE,strlen(BYEBYE),0);
                closesocket(sd2);
                cout << "Client disconnected" << endl;
                break;
            }
            else
            {
                send(sd2,UNKNOWN,strlen(UNKNOWN),0);
            }
        }
    }
    return 0;
}

const int MAXCLI=10;

int main()
{
    WSADATA WSAData;
    WSAStartup(0x0101,&WSAData);
    int sd=socket(AF_INET,SOCK_STREAM,0);
    if(sd<0)
    {
        cout << "Could not create socket: " << strerror(errno) << endl;
    }
    int status;
    struct sockaddr_in local;
    local.sin_family=AF_INET;
    local.sin_port = htons(1234);
    local.sin_addr.s_addr = INADDR_ANY;
    status=bind(sd,(struct sockaddr *)&local,sizeof(local));
    if(status<0)
    {
        cout << "Could not bind socket: " << strerror(errno) << endl;
    }
    status=listen(sd,5);
    if(status<0)
    {
        cout << "Could not listen to socket: " << strerror(errno) << endl;
    }
    int sd2[MAXCLI];
    int n=0;
    while(1)
    {
        sd2[n]=accept(sd,0,0);
        if(sd2[n]<0)
        {
            cout << "Could not accept socket: " << strerror(errno) << endl;
        }
        cout << "Client connected" << endl;
        DWORD id;
        CreateThread(0, 0, client, (LPVOID)&sd2[n], 0, &id);
        n=(n+1)%MAXCLI;
    }
    closesocket(sd);
    WSACleanup();
    return 0;
}
Avatar billede Slettet bruger
24. maj 2007 - 16:02 #5
Tak for det - men jeg glemte vist at fortælle, at programmet skal køre på linux. Ændrer det noget?

Du må gerne smide et svar.
Avatar billede arne_v Ekspert
24. maj 2007 - 16:04 #6
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include <windows.h>
#include <errno.h>

void get(char *hostname,int port,char *path, char *fnm)
{
  FILE *fp;
  int sd,status,len,first,tmp;
  char cmd[512],resp[51200],*body;
  struct sockaddr local,remote;
  struct hostent *hostinfo;
  /* create socket */
  sd=socket(AF_INET,SOCK_STREAM,0);
  if(sd<0) {
      printf("Error creating socket: %s\n",strerror(errno));
      goto fin;
  }
  /* bind socket */
  local.sa_family=AF_INET;
  memset(local.sa_data,0,sizeof(local.sa_data));
  status=bind(sd,&local,sizeof(local));
  if(status<0) {
      printf("Error binding socket: %s\n",strerror(errno));
      goto fin;
  }
  /* lookup host */
  hostinfo=gethostbyname(hostname);
  if(!hostinfo) {
      printf("Error looking up host: %s\n",hostname);
      goto fin;
  }
  /* connect to host */
  remote.sa_family=hostinfo->h_addrtype;
  memcpy(remote.sa_data+2,hostinfo->h_addr_list[0],hostinfo->h_length);
  *((short *)remote.sa_data)=port;
  tmp=remote.sa_data[0];
  remote.sa_data[0]=remote.sa_data[1];
  remote.sa_data[1]=tmp;
  status=connect(sd,&remote,sizeof(remote));
  if(status!=0) {
      printf("Error connecting to host: %s port: %d\n",hostname,port);
      goto fin;
  }
  /* send GET request */
  sprintf(cmd,"GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n",path,hostname);
  status=send(sd,cmd,strlen(cmd),0);
  if(status<0) {
      printf("Error sending GET request\n");
      goto fin;
  }
  /* read response */
  fp = fopen(fnm,"wb");
  first = 1;
  while ((len=recv(sd,resp,sizeof(resp),0))>0) {
      if(first) {
          body = strstr(resp,"\r\n\r\n") + 4;
          first = 0;
      } else {
          body = resp;
      }
      fwrite(body,len-(body-resp),1,fp);
  }
  fclose(fp);
fin:
  closesocket(sd);
  return;
}

int main(int argc,char *argv[])
{
  WSADATA WSAData;
  WSAStartup(0x0101,&WSAData);
  get("www.eksperten.dk",80,"/img/elogo.png","elogo.png");
  WSACleanup();
  return 0;
}
Avatar billede Slettet bruger
24. maj 2007 - 16:09 #7
Ja, så begynder det at ligne min perl proxy. Smid gerne svar.
Avatar billede arne_v Ekspert
24. maj 2007 - 16:10 #8
ja lidt

#include <windows.h>

erstattes af

#include <sys/socket.h>
#include <fcntl.h>
#include <netdb.h>

og closesocket erstattes af socket og alle linier med WSA skal slettes
Avatar billede arne_v Ekspert
24. maj 2007 - 16:11 #9
svar
Avatar billede arne_v Ekspert
24. maj 2007 - 16:12 #10
eksemplerne er lidt blandede i baade funktionalitet og kvalitet

men bare det at du kender funktions navnene goer jo at du kan bruge man
Avatar billede arne_v Ekspert
24. maj 2007 - 16:13 #11
ja og threading er ogsaa anderledes i Linux

her er noget pthreads kode:

#include <pthread.h>

#include <iostream>

using namespace std;

void *x(void *a)
{
    cout << "x" << endl;
    return NULL;
}

void *y(void *a)
{
    cout << "y" << endl;
    return NULL;
}

int main()
{
    pthread_t xy1,xy2;
    pthread_create(&xy1, NULL, x, NULL);
    pthread_create(&xy2, NULL, y, NULL);
    void *retval1,*retval2;
    pthread_join(xy1,&retval1);
    pthread_join(xy2,&retval2);
    return 0;
}
Avatar billede Slettet bruger
24. maj 2007 - 16:19 #12
Perfekt, tak for det.

Hvor finder du den slags? Jeg mangler lidt et www.c++.com :) ligesom php.net for php og cpan.org/perldocs for perl.
Avatar billede arne_v Ekspert
24. maj 2007 - 16:33 #13
alt koden ovenfor er kode fra mit eget arkiv over kode lavet til tidligere
spoergsmaal her paa E

normalt er man teksten til den enkelte funktion ganske glimrende - hvis du kan finde det
rette funktionsnavn, saa skal du nok naa frem
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester