dayslepr Skrevet 2. april 2006 Del Skrevet 2. april 2006 (endret) hei, jeg kunne trengt en HTTP-server skrevet i C edit: ..å si "server" blir kanskje litt galt; da den mer er en slags proxy eller "oversetter" kort (ikke ferdig) beskrivelse her: http://nostdal.org:6060/~lars/programming/...aromyxo/com.txt ..og litt av implementasjonen her: http://nostdal.org:6060/~lars/programming/...xo/com/socket.c noen som kan hjelpe? Endret 2. april 2006 av dayslepr Lenke til kommentar
kimla Skrevet 3. april 2006 Del Skrevet 3. april 2006 hei,jeg kunne trengt en HTTP-server skrevet i C edit: ..å si "server" blir kanskje litt galt; da den mer er en slags proxy eller "oversetter" kort (ikke ferdig) beskrivelse her: http://nostdal.org:6060/~lars/programming/...aromyxo/com.txt ..og litt av implementasjonen her: http://nostdal.org:6060/~lars/programming/...xo/com/socket.c noen som kan hjelpe? 5857177[/snapback] Legg de filene på en server som kjører på port 80 eller noe, ellers kommer jeg ikke til dem på jobben Lenke til kommentar
dayslepr Skrevet 3. april 2006 Forfatter Del Skrevet 3. april 2006 (endret) okei Aromyxo - Com============= Basically a lightweight HTTP-server written in C for maximum speed and portability that: * Reads HTTP-requests. * Converts HTTP-messages to a given format. * Calls a foreign function (implemented as a C callback) with a pointer to the converted data, that generates a response in the same format. * Converts the response returned from the foreign function back to a "regular" HTTP-message. * Sends the "decoded" response back to the client. This HTTP-request: GET / HTTP/1.1\r\n Host: symbolicweb.org\r\n Connection: close\r\n Accept-Encoding: gzip\r\n\r\n ..could for instance be converted to a string like this: ((method . get) (url . "/") (version . "1.1") (connection . close) (accept-encoding "gzip")) The point being that this can be read directly in Lisp by the function `read', giving you the data-structure to play with. In other languages one have stuff like `eval' that does the same thing. Since `method' only can have a finite set of values, it's value is not formatted as a string. The same goes for headers like `content-length'. The body of the request (if any) should be put in an association with the key-name `body'. Fur chunked transfers, it should first send the headers - then call a foreign function for each chunk. I'm thinking this thing could be extensible by not having the format hardcoded, but instead use #define-macros for the syntax-parts it is to use. Like for instance: #define HEADERS_START "((" #define HEADERS_END "))" #define HEADER_START '(' #define HEADER_END ')' #define KEY_VALUE_DELIMITER '.' etc. There are other ways to achieve extensibility like this; this is just a suggestion. Suggestions =========== Simple unithreaded at first - then multithreading with pools? It must run under Linux, and should be written so it can be ported later. /* gcc -Wall -shared -fPIC -g socket.c -o libaromyxo.so */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/wait.h> #include <signal.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/wait.h> #include <sys/epoll.h> #include <signal.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #define ESTIMATED_NUMBER_OF_CONNECTIONS 100 #define MAX_EVENTS 100 // how much extra to allocate when buffer is full. #define RECV_BUFFER_STEP_SIZE 5 int amTCPServerSocket(int port, int backlog) { int s; if((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) { perror("amTCPServerSocket, socket"); return -1; } fcntl(s, F_SETFL, O_NONBLOCK); int yes = 1; if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { perror("setsockopt"); return -1; } struct sockaddr_in my_addr; my_addr.sin_family = AF_INET; my_addr.sin_port = htons(port); my_addr.sin_addr.s_addr = INADDR_ANY; memset(&(my_addr.sin_zero), '\0', 8); if(bind(s, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) { perror("amTCPServerSocket, bind"); return -1; } if(listen(s, backlog) == -1) { perror("amTCPServerSocket, listen"); return -1; } return s; } // amTCPServerSocket inline int amAccept(int socket) { // TODO: Read address here - or do it later? int sd = accept(socket, NULL, 0); if(sd == -1) perror("amAccept, accept"); return sd; } // amAccept typedef struct { int socket; char status; unsigned int size; void* data; } DataBlock; inline DataBlock* amRecvUntilWouldBlock(int socket) /* Recieves data from socket until reads would block (EAGAIN). NOTE: This function returns malloced data that needs to be freed. */ { unsigned int read_until_now = 0; int read; DataBlock* data_block = malloc(sizeof(DataBlock)); data_block->socket = socket; unsigned int remaining = RECV_BUFFER_STEP_SIZE * 2; data_block->data = malloc((sizeof(char) * RECV_BUFFER_STEP_SIZE * 2)); //printf("amRecvUntilWouldBlock, start - will read from socket: %d\n", socket); while((read = recv(socket, data_block->data + read_until_now, RECV_BUFFER_STEP_SIZE, 0)) > 0) { read_until_now += read; remaining -= read; printf("amRecvUntilWouldBlock, socket: %d, read: %d, read_until_now: %d, remaining: %d\n", socket, read, read_until_now, remaining); if(remaining <= (RECV_BUFFER_STEP_SIZE / 2) - 1) { data_block->data = realloc(data_block->data, sizeof(char) * (read_until_now + remaining + RECV_BUFFER_STEP_SIZE)); remaining = remaining + RECV_BUFFER_STEP_SIZE; printf("amRecvUntilWouldBlock, reallocating, new space remaining: %d\n", remaining); } } data_block->status = read; data_block->size = read_until_now; //printf("amRecvUntilWouldBlock, status: %d\n", read); //perror("amRecvUntilWouldBlock, perror: "); //printf("amRecvUntilWouldBlock, end\n"); return data_block; } // amRecvUntilWouldBlock typedef void (*AMDispatcherForeign)(DataBlock** data_blocks, unsigned int num); volatile char am_listening = 0; int amDispatcherC(int server_socket, AMDispatcherLisp amDispatcherLisp) { int n; unsigned int n_active; int epfd = epoll_create(ESTIMATED_NUMBER_OF_CONNECTIONS); int incoming_socket; int nfds; struct epoll_event ev; struct epoll_event events[MAX_EVENTS]; DataBlock* data_blocks[MAX_EVENTS]; ev.events = EPOLLIN | EPOLLPRI; ev.data.fd = server_socket; if(epoll_ctl(epfd, EPOLL_CTL_ADD, server_socket, &ev) == -1) { perror("amDispatcherC, epoll_ctl (server_socket)"); return errno; } am_listening = 1; while(am_listening) { n_active = 0; if((nfds = epoll_wait(epfd, events, MAX_EVENTS, -1)) == -1) { perror("amDispatcherC, epoll_wait"); return errno; } for(n = 0; n < nfds; ++n) { if(events[n].data.fd == server_socket) { // New incoming connection on listening socket // if((incoming_socket = amAccept(server_socket)) == -1) { // TODO: Some other way of letting the Lisp-side know about this? perror("amDispatcherC, amAccept (incoming_socket)"); continue; } fcntl(incoming_socket, F_SETFL, O_NONBLOCK); ev.events = EPOLLIN | EPOLLPRI | EPOLLET; ev.data.fd = incoming_socket; if(epoll_ctl(epfd, EPOLL_CTL_ADD, incoming_socket, &ev) == -1) { perror("amDispatcherC, epoll_ctl (incoming_socket)"); return errno; } } else { // Activity on an already connected socket // data_blocks[n_active++] = amRecvUntilWouldBlock(events[n].data.fd); //printf("amDispatcherC will dispatch socket %d\n", events[n].data.fd); } } printf("callback!\n"); amDispatcherLisp(data_blocks, n_active); // Clean up after Lisp-side is done with data // int i; for(i = 0; i < n_active; i++) { free(data_blocks[i]->data); free(data_blocks[i]); } } return 0; } // amDispatcherC Endret 3. april 2006 av dayslepr Lenke til kommentar
dayslepr Skrevet 7. april 2006 Forfatter Del Skrevet 7. april 2006 hm - så dårlig respons; da fortsetter jeg på denne selv til uka tenker jeg ... :} Lenke til kommentar
Me sjøl Skrevet 17. april 2006 Del Skrevet 17. april 2006 Webservere i C finnes det mange av, men det høres ut som det du ønsker er en HTTP-parser som returnerer en eller annen form for ast eller hashstruktur og kan konvertere denne tilbake til valid http? Lenke til kommentar
dayslepr Skrevet 18. april 2006 Forfatter Del Skrevet 18. april 2006 (endret) jau - noe sånnt men jeg har lagt denne idéen på hylla intil videre; det blir litt mer styr m.t.p. encoding og annet som jeg ikke gidder å bruke tid på nå (edit: eller, uhm - encoding løste seg visst noen strakser etter jeg skrev denne, men les neste "edit:") tror uansett det er mulig å få til det jeg er ute etter uten denne tingen edit: eller med nærmere ettertanke tror jeg dette er en premature optimization .. så fort jeg får ferdig litt andre ting først, ordner jeg denne optimaliseringen selv.. jeg tror jeg må gjøre det selv (for å bli fornøyd?) uansett *eeep* ...alle "rister på hue" og lurer på hvorfor jeg vil dette (hvor ting ender langt frem i tid?); så jeg "får vel vise dem" - da forklaringen(e) vil bli lengre enn selve koden alikevell (hint: >10k klienter, massiv multitasking med portabelt GUI-frontend) Endret 19. april 2006 av dayslepr Lenke til kommentar
dayslepr Skrevet 22. april 2006 Forfatter Del Skrevet 22. april 2006 (endret) Da har jeg så småning om (er det det de sier i sverige?) begynnt på prosjektet: http://nostdal.org/sw/wiki/EPServer det ser ut til at jeg gjør det litt lettere enn jeg hadde tenkt å gjøre det i utgangspunktet; jeg sender i stedet socketene over til foreign-siden (Lisp i mitt tilfele) og leser/parser ting der .. så kan jeg heller porte den "parse-biten" til C siden .. det viktigste er at jeg har en veldig skalerbar "event-basert async-server-ting-sak", og det får jeg .... Endret 22. april 2006 av dayslepr Lenke til kommentar
Anbefalte innlegg
Opprett en konto eller logg inn for å kommentere
Du må være et medlem for å kunne skrive en kommentar
Opprett konto
Det er enkelt å melde seg inn for å starte en ny konto!
Start en kontoLogg inn
Har du allerede en konto? Logg inn her.
Logg inn nå