... i przepisałem kawałek kodu z książki ;)
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
// printfy
#include <stdlib.h>
// exit()
#include <string.h>
//zawiera definicje memset()
#define SERVER_PORT 4095
#define BUF_SIZE 4096
#define QUEUE_SIZE 10
fatal(char *x)
{
printf("%s", x);
exit(1);
}
int main(int argc, char **argv)
{
char bufor[BUF_SIZE];
int gniazdo, one = 1, i;
struct hostnet *ServerInfo;
struct sockaddr_in NrIP;
memset(&NrIP, 0, sizeof(NrIP)); // wypełniam zerami NrIP
NrIP.sin_family = AF_INET; // dziedzina adresów: IPv4
NrIP.sin_addr.s_addr = htonl(INADDR_ANY);
/* może korzystać z każdego numeru IP jaki znajdzie dla danego
komputera. W praktyce oznacza to, że gdy są dwa interfejsy
(np. sieć lokalna z kabelka i wifi(internet) to obsługiwane
będą połączenia od obu tych interfejsów */
NrIP.sin_port = htons(SERVER_PORT); //nr portu
gniazdo = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
/* SOCK_STREAM - dane przesyłane strumieniowo
IPPRO_TCP - z wykorzystaniem protokolu TCP */
if (gniazdo < 0)
fatal("Blad utworzenia gniazda\n");
setsockopt(gniazdo, SOL_SOCKET, SO_REUSEADDR, (char*) &one, sizeof(one));
/*SOL_SOCKET - operacja ma być wykonana na poziomie gniazda
(a nie na przez oprogramowanie IPv4 lub TCP)
SO_REUSEADDR - pozwalamy na wiele równoczesnych połączeń serwera.
Ustawiamy tą wartość (one). Ostatni parametr mówi jak
duża jest zmienna one */
//zmienna one nie jest już dalej potrzebna.
one = bind(gniazdo, (struct sockaddr *) &NrIP, sizeof(NrIP));
if (one < 0)
fatal("Blad przyporzadkowania adresu IP do gniazda\n");
// maksymalna ilość żądań połączenia
one = listen(gniazdo, QUEUE_SIZE);
if (one < 0)
fatal("Error: listen()\n");
//--------------------------------------------------------------
// gniazdo gotowe do pracy
//--------------------------------------------------------------
while (1)
{
one = accept(gniazdo, 0, 0);
/* argumenty 2 i 3 mogą określać strukturę sockaddr, która
zostałaby wypełniona danymi nt połącznia - niepotrzebne nam to. */
if (one < 0)
fatal("Error: accept()\n");
read(one, bufor, BUF_SIZE); // odczytanie nazwy przychodzącego pliku
i = -1;
if (!strcmp(bufor,"LIST")) i = 0;
if (!strcmp(bufor "GET")) i = 1;
if (!strcmp(bufor "CLOSE")) i = 2;
switch (i)
{
case 0:
printf("Odebralem LIST\n");
break;
case 1:
printf("Odebralem GET\n");
break;
case 2:
printf("Odebralem CLOSE\n");
break;
default:
printf("Zly format polecenia\n");
break;
};
close(one); // rozlaczenie
}
}
Jest to szkielet, który jest jeszcze mniej funkcjonalny, niż jego odpowiednik w książce Tanenbauma, ale delikatnie ukształtowany pod kształt tego, co chcę osiągnąć - przynajmniej tak myślę. No i przesadnie wręcz obkomentowany.
EDIT: Wiele więcej problemów niż z samym powyższym kodem, miałem z jego czytelnym zamieszczeniem - dlatego zresztą notka jest tak krótka i skąpa. Posłużyłem się w końcu tym sposobem , ale nie jest do końca skuteczny - między liniami kodu powstały trzyakapitowe przerwy... Wynik wybitnie nie jest zadowalający.
EDIT2: Znalazłem wreszcie świetne narzędzie: www.blogtrog.com. Wada? Nie obsługuje kodu w C/C++... trudno. Grunt, że jest czytelnie i nie trzeba nic ręcznie poprawiać. Victory!