czwartek, 28 maja 2009

Serwer

Sesja zbliża się wielkimi krokami, trza zabrać się do pracy :) Oczywiście to co najnudniejsze automatycznie spada na sam koniec listy rzeczy do zrobienia i tym sposobem zabrałem się za pisanie zadanka z sieci. Zaopatrzywszy się w odpowiednie zaplecze teoretyczne, włączyłem muzykę...




... 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!

Brak komentarzy: