/ Forside / Teknologi / Udvikling / C/C++ / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
C/C++
#NavnPoint
BertelBra.. 2425
pmbruun 695
Master_of.. 501
jdjespers.. 500
kyllekylle 500
Bech_bb 500
scootergr.. 300
gibson 300
molokyle 287
10  strarup 270
C++ og GET/POST til URL og validere output
Fra : KV


Dato : 24-03-07 23:35

Jeg er ved at kode et helt simpelt program til Linux og har brug for, at
kunne henholdsvis GET og POST til en given URL og indlæse resultatet i en
variabel.
Jeg vil helst ikke gøre brug af 3. parts source kode eller programmer
(f.eks. curl) men undgår jeg det? Det er vel ikke bare at åbne en fil
(ligesom fopen med PHP)?



 
 
Arne Vajhøj (25-03-2007)
Kommentar
Fra : Arne Vajhøj


Dato : 25-03-07 00:29

KV wrote:
> Jeg er ved at kode et helt simpelt program til Linux og har brug for, at
> kunne henholdsvis GET og POST til en given URL og indlæse resultatet i en
> variabel.
> Jeg vil helst ikke gøre brug af 3. parts source kode eller programmer
> (f.eks. curl) men undgår jeg det? Det er vel ikke bare at åbne en fil
> (ligesom fopen med PHP)?

Du åbner en socket til port 80, skriver en GET eller POST request
og læser response.

GET format er:

sprintf(cmd,"GET %s HTTP/1.1\r\nHost: %s\r\nConnection:
close\r\n\r\n",path,hostname);

POST format er:

sprintf(cmd,"POST %s HTTP/1.1\r\nHost: %s\r\nConnection:
close\r\nContent-Length: %d\r\n\r\n%s\r\n",
path,hostname,strlen(args),args);

Arne

Robert Bauck Hamar (25-03-2007)
Kommentar
Fra : Robert Bauck Hamar


Dato : 25-03-07 01:43

Arne Vajhøj wrote:

> KV wrote:
>> Jeg er ved at kode et helt simpelt program til Linux og har brug for, at
>> kunne henholdsvis GET og POST til en given URL og indlæse resultatet i en
>> variabel.

Finn ut hvordan sockets virker på din maskin. BSD-lignende utgaver finnes
for flere UNIX-varianter samt Windows.

>> Jeg vil helst ikke gøre brug af 3. parts source kode eller programmer
>> (f.eks. curl) men undgår jeg det? Det er vel ikke bare at åbne en fil
>> (ligesom fopen med PHP)?

BSD-sockets oppfører seg i stor grad som filer i UNIX.

> Du åbner en socket til port 80, skriver en GET eller POST request
> og læser response.

Hele HTTP-standarden finnes på w3.org

> GET format er:
>
> sprintf(cmd,"GET %s HTTP/1.1\r\nHost: %s\r\nConnection:
> close\r\n\r\n",path,hostname);
>
> POST format er:
>
> sprintf(cmd,"POST %s HTTP/1.1\r\nHost: %s\r\nConnection:
> close\r\nContent-Length: %d\r\n\r\n%s\r\n",
> path,hostname,strlen(args),args);

Her kommer et eksempel på en GET. Dette virker i Linux 2.6, men den har
ingen feilsjekking. I C er alle strukturene structs, og må opprettes
med «struct sockaddr». I tillegg skal/bør du bruke select før read og
write.

Alle disse detaljene tilsier vel at det er lurt å bruke et eller annet
bibliotek? Jeg har ikke testet koden på andre systemer.

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>

int main() {
//Lag socket (mye av det samme som filedescriptor fra open())
int sock = socket(PF_INET, SOCK_STREAM, 0);
// DNS-oppslag (finner IP-adressen fra URL)
hostent *add = gethostbyname("www.riksmalsforbundet.no");

// IPv6: sockaddr_in6 sin
sockaddr_in sin;
memset(&sin, 0, sizeof sin);

// Internet IPv4.
// sin.sin6_family = AF_INET6 for IPv6.
// Bør matche add->h_addrtype
sin.sin_family = AF_INET;

// htons = host to network short. Tar hånd om endian-ting.
// 80 er standard http-port
sin.sin_port = htons(80);

// IPv4-adresse. GÃ¥r fryktelig galt hvis add->h_addrtype != AF_INET
// add->h_addr er en char* med bytene i adressen
// IPv6: sin.sin6_addr.s6_addr er en char[16]. se ipv6(7)
sin.sin_addr.s_addr = *reinterpret_cast<u_int32_t*>(add->h_addr);

// Opprette forbindelse
connect(sock, reinterpret_cast<sockaddr*>(&sin), sizeof sin);

// Skrive request.
char buf[] = "GET /ordliste/?T=sok&soketype=S&q=ord HTTP/1.1\r\n"
"Host: www.riksmalsforbundet.no\r\n"
"Connection: close\r\n\r\n";
write(sock, buf, sizeof buf);

char ans[1024];
int s;
// Lese svar
while((s = read(sock, ans, sizeof ans)) > 0)
// Skrive til stdout.
write(1, ans, s);
}

--
Robert Bauck Hamar
Semikolon markerer en litt kortere pause enn punktum; det kan bare
stå mellom selvstendige setninger. Det er en moderne uskikk å bruke
semikolon istedenfor kolon. Følg ikke den uskikken!

KV (25-03-2007)
Kommentar
Fra : KV


Dato : 25-03-07 15:54

> Hele HTTP-standarden finnes på w3.org

Jeg har fundet denne, http://www.ietf.org/rfc/rfc2616.txt som vel bør være
HTTP/1.1 standarden?

> Her kommer et eksempel på en GET. Dette virker i Linux 2.6, men den har
> ingen feilsjekking. I C er alle strukturene structs, og må opprettes
> med «struct sockaddr». I tillegg skal/bør du bruke select før read og
> write.
>
> Alle disse detaljene tilsier vel at det er lurt å bruke et eller annet
> bibliotek? Jeg har ikke testet koden på andre systemer.

Har du nogle forslag? Jeg har fundet denne, http://rudeserver.com/socket/
men kan ikke rigtigt gennemskue hvilke Linux systemer den bør kunne fungere
på?

[CUT]
> char ans[1024];
> int s;
> // Lese svar
> while((s = read(sock, ans, sizeof ans)) > 0)
> // Skrive til stdout.
> write(1, ans, s);

Tak for eksemplet. Det fik mig helt sikkert videre.



Arne Vajhøj (25-03-2007)
Kommentar
Fra : Arne Vajhøj


Dato : 25-03-07 16:13

KV wrote:
>> Hele HTTP-standarden finnes på w3.org
>
> Jeg har fundet denne, http://www.ietf.org/rfc/rfc2616.txt som vel bør være
> HTTP/1.1 standarden?

Ja. HTTP er IETF ikke W3C.

> Tak for eksemplet. Det fik mig helt sikkert videre.

Et andet eksempel:

void get(char *hostname,int port,char *path)
{
int sd,status,len,ix,tmp;
char cmd[512],resp[51200];
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\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 */
ix=0;
while ((len=recv(sd,resp+ix,sizeof(resp)-ix-1,0))>0) {
ix = ix + len;
}
resp[ix]='\0';
printf("%s",resp);
fin:
close(sd);
return;
}

Linux includes:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

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

Arne

KV (25-03-2007)
Kommentar
Fra : KV


Dato : 25-03-07 19:22

>> Tak for eksemplet. Det fik mig helt sikkert videre.
> Et andet eksempel:
[CUT]

Også tak for denne Jeg har nok nu til at kunne klare det basale.



Robert Bauck Hamar (26-03-2007)
Kommentar
Fra : Robert Bauck Hamar


Dato : 26-03-07 02:30

KV wrote:
>> Her kommer et eksempel på en GET. Dette virker i Linux 2.6, men den har
>> ingen feilsjekking. I C er alle strukturene structs, og må opprettes
>> med «struct sockaddr». I tillegg skal/bør du bruke select før read og
>> write.
>>
>> Alle disse detaljene tilsier vel at det er lurt å bruke et eller annet
>> bibliotek? Jeg har ikke testet koden på andre systemer.
>
> Har du nogle forslag?

Nei.

> Jeg har fundet denne, http://rudeserver.com/socket/
> men kan ikke rigtigt gennemskue hvilke Linux systemer den bør kunne
> fungere på?

Synes ikke dette er noe å satse på. Ser ut som et mindre godt eksempel på en
C++-wrapper rundt socket-biblioteket. Da kan man like gjerne gjøre det
selv.

Jeg kikket litt på det og fant rare ting:
* Biblioteket er visstnok GPL, men kildekoden finner jeg ikke
* Biblioteket støtter ikke std::string
* Socket::reads() returnerer en const char*, men hvor(dan) er denne
allokert?
* Hvorfor må man undersøke returverdier når man kunne brukt exceptions?

Til gjengjeld støtter det også SSL.

Dessuten er det heller et HTTP-bibliotek som er praktisk. Ã… sende en
HTTP-request er enkelt nok, men når man skal ta imot informasjon fra
nettet, må man alltid være forberedt på at svaret ikke nødvendigvis er til
å stole på. Ting må sjekkes, og det er fornuftig å bruke testede
biblioteker fremfor å finne opp hjulet.

Et annet eksempel på at ting kan gå galt, er utallige cgi-script som
kontrollerer at en epostadresse virkelig ser ut som en epostadresse – i
programmørens tolkning; f.eks. er det mange som tror at '+' ikke er tillatt
i en epostadresse.

> Tak for eksemplet. Det fik mig helt sikkert videre.

Sitter du på en linux, kan du alltid prøve kommandoen «man funksjonsnavn».
Funksjoner skal være i seksjon 2 (systemkall) eller 3 (C-bibliotek), så man
må av og til skrive f.eks. «man 2 write». Ellers: «man 7 ip» og «man 7
ipv6»

--
Robert Bauck Hamar
Semikolon markerer en litt kortere pause enn punktum; det kan bare
stå mellom selvstendige setninger. Det er en moderne uskikk å bruke
semikolon istedenfor kolon. Følg ikke den uskikken!

Søg
Reklame
Statistik
Spørgsmål : 177552
Tips : 31968
Nyheder : 719565
Indlæg : 6408849
Brugere : 218887

Månedens bedste
Årets bedste
Sidste års bedste