Witam,
Dostałem takie zadanie. Stworzyć serwer HTTP w języku C, który będzie dostarczał plik index.html w standardzie HTTP 0,9.. Czyli wyświetlał cały kod na ekranie.
Znalazłem kod serwera na jednej ze stron:
[code]
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main()
{
int sock, polaczenie, bajty_odebrane, true=1; //deklarujemy potrzebne rzeczy: sock - tutaj będziemy mieli informację o tym który port i adres ip są ze sobą powiązane
// polaczenie - tutaj będzie informacja o aktualnie otwartym połączeniu
// bajty_odebrane - zmienna pomocnicza przy odbieraniu danych
// true - zmienna używana przy ustawianiu opcji gniazda sock
char dane_wysylane[1024], dane_odbierane[1024]; //zmienne, w których będziemy przetrzymywać odebrane dane i dane do wysłania, dodatkowo ograniczamy ich długość do 1024
struct sockaddr_in adres_serwera,adres_klienta; //deklarujemy strukturę sockaddr_in, w której będziemy trzymać adresy serwera i klienta
int sin_size;
if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) //ustawiamy gniazdo sock na używanie protokołu IPv4 (AF_INET) oraz wybieramy typ gniazda (odpowiednio SOCK_STREAM i 0)
{ //jeśli funkcja sock zwróci błąd wyświetli się błąd i program się zamknie
perror("Socket");
exit(1);
}
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int)) == -1) //ustawiamy opcję SO_REUSEADDR w gnieździe sock na wartość zmiennej true, czyli 1, podobnie jak wyżej
{ //jak wystąpi błąd pojawi się komunikat i program się zakończy
perror("Setsockopt"); //SO_REUSEADDR - Normalnie funkcja bind() zwraca błąd jeśli spróbujemy związać gniazdo z adresem,
exit(1); //który jest aktualnie w użyciu. Załóżmy, że gniazdo o adresie 127.0.0.1 i porcie 1111 jest
} //aktualnie w stanie TCP_FIN. Jeśli chcielibyśmy z tym adresem skojarzyć jakieś inne gniazdo
//nie czekając na zakończenie czasochłonnego procesu zamykania połączenia to musimy włączyć
//właśnie tą opcję.
//Ważna uwaga: nawet SO_REUSEADDR nie pomoże jeśli jakies gniazdo
//nasłuchuje (LISTEN) na danym adresie.
//ustawiamy adres serwera
adres_serwera.sin_family = AF_INET; //wybieramy protokuł IPv4
adres_serwera.sin_port = htons(5000); //ustawiamy port, w tym przypadku jest to port 5000
adres_serwera.sin_addr.s_addr = INADDR_ANY; //w srukturze serwera ustawiamy pozycję sin_addr.s_addr na INADDR_ANY, aby każdy mógł coś do nas napisać
bzero(&(adres_serwera.sin_zero),8);
if (bind(sock, (struct sockaddr *)&adres_serwera, sizeof(struct sockaddr)) == -1) //bindujemy (wiążemy) do naszego gniazda sock, adres naszego serwera, tak jak wcześniej gdy błąd -> komunikat i zkończenie
{
perror("Unable to bind");
exit(1);
}
if (listen(sock, 5) == -1) //sprawiamy, iż nasz serwer zacznie nasłuchiwać na gnieździe sock, to jest na porcie 5000 o adresie IP serwera, dodatkowo ustawiliśmy długość kolejki połączeń na 5
{
perror("Listen");
exit(1);
}
printf("\nSerwer TCP oczekuje na klienta na porcie 5000"); //komunikat w oczekiwaniu na podłączenie się jakiś klientów
fflush(stdout); //zapisujemy dane bufora stdout (to co wyświetla się na ekranie), przez co go opróżniamy, żeby bez problemu zacząć pracę z klientem
while (1)
{
sin_size = sizeof(struct sockaddr_in);
polaczenie = accept(sock, (struct sockaddr *)&adres_klienta,&sin_size); //funkcja accept() blokuje dalcze działanie programu, dopóki nei podłączy się jakiś klient, wtedy następuje
//wpisanie danych klienta do struktury wskazywanej przez adres_klienta. sin_size, to wielkość struktury sockaddr_in
//ponadto funckja accept() zwróci do zmiennej polaczenie dyskryptor gniazda, którego będziemy używać do komunikacji z tym klientem
printf("\nPołączenie z (%s, %d)",inet_ntoa(adres_klienta.sin_addr),ntohs(adres_klienta.sin_port)); //komunikat o udanym połączeniu z klientem o adresie IP i na jakim porcie
while (1)
{
printf("\n WYŚLIJ (q albo Q aby zakończyć): "); //linia zachęty, do wprowadzenia danych do wysłania, q albo Q zakańcza program
gets(dane_wysylane); //przechwytujemy sąg znaku wpisywany z klawiatury, do zmiennej dane_wysylane. wprowadzanie danych kończy się enterem
if (strcmp(dane_wysylane, "q") == 0 || strcmp(dane_wysylane, "Q") == 0) //pętla warunkowa kończąca program jeśli wprowadziliśmy z klawiatury q lub Q
{
send(polaczenie, dane_wysylane, strlen(dane_wysylane), 0); //funkcja send wysyłająca do klienta informację o tym iż zakończyliśmy działanie programu
close(polaczenie); //zamknięcie połączenia z klientem
break; //wyjście z pętli while
}
else
{
send(polaczenie, dane_wysylane, strlen(dane_wysylane), 0); //wysyłanie komunikatu, jeśli nie był on q lub Q, o długości strlen(dane_wysylane)
}
bajty_odebrane = recv(polaczenie, dane_odbierane,1024,0); //odebranie danych od klienta i wpisywanie ich do zmiennej pomocniczej bajty_odebrane
dane_odbierane[bajty_odebrane] = '\0'; //jako, że nie wiemy jak długi komunikat odebraliśmy, skracamy cały string bajty_odebrane, który ma długość 1024 do momentu kiedy znakiem będzie \0,
///ponieważ ten znak na końcu dodaje funkcja gets, której używamy
if (strcmp(dane_odbierane, "q") == 0 || strcmp(dane_odbierane, "Q") == 0) //sprawdzamy, czy przypadkiem klient nie zakończył swojego działania
{
close(polaczenie); //zamykamy połączenie jeśli klient zakończył swoje działanie
break; //wychodzimy z pętli while
}
else
{
printf("\n ODEBRANO = %s", dane_odbierane); //wyświetlamy na wyjściu otrzymany komunikat jeśli, jeśli klient nie zakończył swojego działania
}
fflush(stdout); //zapisujemy bufory wyjścia i je tym samym opróżniamy
}
}
close(sock); //zamykamy gniazdo sock
return 0; //kończymy działanie programu
}
[/code]
No ale nie ma gdzieś tutoriala jak własnoręcznie napisać kod sewera?
I jak zaimplementować tam opcję tego wyświetlania klientowi pliku index.html..
Może ktoś ma jakiś najprostszy kod serwera bo ten to chyba długaśny strasznie.. Nie mam całkowicie pojęcia jak się za to zabrać.. Proszę o jakieś wskazówki. I nie to że nie szukałem. Szukam cały czas. Próbuje ale bezskutecznie :(