Semafory Semafor w programowaniu jest abstrakcją o zastosowaniu zaczerpniętym z działalności kolei. Gdy zasobów jest na tyle mało, że trzeba ich użyciem się dzielić (typowych zasobów jest zawsze za mało), naturalne jest wprowadzenie znaczników zajętości. W kolejnictwie semafory informują o zajętości toru, stacji itp.. Np. jeśli dany jest pojedynczy odcinek torów na którym powinien znajdować się najwyżej jeden pociąg, inne pociągi muszą czekać, aż semafor przyjmie stan zezwalający na zajęcie tego odcinka torów. W wersji komputerowej semafor może być przechowywaną zmienną typu int. Dany proces czeka aż zmienna ta przyjmie wartość zero. Gdy proces uzyskuje dostęp do zasobu ”będącego chronionego semaforem”, podwyższa tą wartość o jeden (inkrementuje). Gdy kończy używanie, odejmuje od tej wartości jeden.
Semafory semget() semctl() semop()
Semafory semget() Funkcja semget() inicjalizuje lub umożliwia dostęp do semaforu. Oto jej prototyp: #include <sys/sem.h> int semget(key_t key, int nsems, int semflg); w przypadku sukcesu funkcja zwraca semid (”semaphore id”) key – wartość klucza stowarzyszona z semaforem nsems – ile elementów ma dany semafor (jego macierz) semflg – definiuje początkowe prawa dostępu, znaczniki kontrolne ( na przykład: 0666 | IPC_CREAT | IPC_EXCL )
#include <sys/types.h> #include <sys/ipc.h> Semafory semget() #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> ... key_t key; int semflg; int nsems; int semid; /* semafor id zwracane przez semget() */
key = ... ; nsems = ... ; semflg = ... ; Semafory semget() key = ... ; nsems = ... ; semflg = ... ; if ((semid = semget(key, nsems, semflg)) == -1) { perror("semget: semget failed"); exit(1); } else ...
Semafory semctl() zmienia charakterystyki danego semaforu int semctl(int semid, int semnum, int cmd, union semun arg); semid – semafor id semnum – wybór semaforu (jego indeks, np. 0,1,...) union semun { /* do operacji kontrolnych semctl() */ int val; struct semid_ds *buf; ushort_t *array; } arg;
Semafory semctl() cmd jest jedną z następujących wartości: GETVAL -- Zwróć wartość pojedynczego semaforu. SETVAL -- Ustaw wartość pojedynczego semaforu. Użyte jest arg.val . GETPID -- Zwróć pid procesu który wykonał ostatnią operację na tym semaforze. GETNCNT -- Zwróć liczbę procesów czekających na to, by wartość semaforu wzrosła. GETZCNT -- Zwróc liczbę procesów czekających na to, by wartość semaforu osiągnęła zero.
Semafory semctl() cmd jest jedną z następujących wartości: GETALL -- zwróć wartości wszystkich semaforów w danej macierzy; użyta jest arg.array . SETALL -- ustaw wartości wszystkich semaforów w danej macierzy; użyta jest arg.array . IPC_STAT -- zwrócona jest informacja o semaforze, zostaje umieszczona w strukturze danych arg.buf (czyli użyty jest obiekt typu semid_ds) . IPC_SET -- Ustawione zostają parametry: uzytkownik, grupa, prawa dostępu. Zostaje użyte arg.buf. IPC_RMID -- Semafor zostanie usunięty.
Semafory - semop() #include <sys/sem.h> /* wykonuje operacje na semaforze */ int semop(int semid, struct sembuf *sops, size_t nsops); semid -- semafor id (zwrócone przez semget() ) sops -- wskaźnik do macierzy struktur (struktura sembuf opisuje operację na semaforze) struct sembuf { ushort_t sem_num; /* numer semaforu */ short sem_op; /* kod operacji */ short sem_flg; /* znacznik operacji */ };
Semafory - semop() Argument nsops określa długość tej macierzy struktur; tym samym określa ile operacji wykona pojedyncze zawołanie semop(). Operacje są wykonywane w następujący sposób: dodatnia wartość int powiększa wartość semafora (o wartość) ujemna wartość int obniża wartość semafora (o wartość), próba ustawienia semafora na mniej niż zero powoduje blokowanie (zawieszenie procesu) lub błąd, w zależności od tego czy włączony jest znacznik IPC_NOWAIT wartość zero oznacza żądanie oczekiwanie aż semafor osiągnie zero
Semafory - semop() znaczniki kontrolne IPC_NOWAIT – zgłasza zakaz blokowania procesu (gdyby operacja nie mogła być wykonana) SEM_UNDO – poszczególne operacje opisane w macierzy struktur zostaną wycofane gdy semop() się załamie (”uda się wszystko albo nic”)
Semafory - semop() po wywołaniu semop() proces (jego dalsze wykonanie) jest blokowany (chyba że użyte jest IPC_NOWAIT); tak długo aż dojdzie do jednej z poniższych sytuacji: semop() się wykona proces otrzyma sygnał semafor zostanie usunięty (np.. komendą ipcrm, lub usunie go inny proces)
Semafory Uwagi: tylko jeden proces na raz może modyfikować semafor. Jeśli kilka procesów spróbuje zrobić to jednocześnie, zostaną wykonane w kolejności o której rozstrzygnie system operacyjny. Jeśli proces modyfikujący semafor padnie, może się zdarzyć że stan semaforu został zmodyfikowany tylko częściowo.
#include <stdio.h> #include <unistd.h> //fork() Semafory - przykład #include <stdio.h> #include <unistd.h> //fork() #include <sys/errno.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> //semget(), semctl() #include <sys/wait.h>
Semafory - przykład main() { int semid; key_t klucz; typedef unsigned short ushort_t; union semun { int val; struct semid_ds *buf; ushort_t *array; } sun; //do operacji kontrolnych, semctl
Semafory - przykład klucz = ftok(".", 110); /* ftok użyty do generacji klucza */ semid=semget(klucz, 3, 0666 | IPC_CREAT);/*tworzy zbior semaforow*/ printf("\nTworzono zbior semaforow o ID=%d\n",semid); if(semid==1) {printf(”nie udalo się!\n”); exit(1); } sun.val=3; semctl(semid, 0, SETVAL, sun); /*ustawienie wartosci */ sun.val=7; semctl(semid, 1, SETVAL, sun); /*ustawienie wartosci */ semctl(semid, 2, SETVAL, sun); /*ustawienie wartosci */ return 0; } /* koniec funkcji main */
Semafory - ipcs ipcs -s ------ Semaphore Arrays -------- key semid owner perms nsems status 0x6e0fc144 98304 rudy 666 3
Semafory – przykład_2 #include<stdlib.h> // #include<sys/types.h> //key_t #include<sys/ipc.h> //ftok() #include<sys/sem.h> //semget() struct sembuf bs = {0, 0, 0}; /* operacje */ main() { int semid, i; key_t klucz; int ktrl;
Semafory – przykład_2 klucz = ftok(".",110); semid = semget(klucz, 3, 0000 ); if(semid == -1) { perror("Blad otwarcia semafora\n"); return 1; } else { /* semget() OK */ printf("\n otwarto zbior semaforow o ID=%d\n\n",semid);
Semafory – przykład_2 printf(" teraz proces o id=%d wypisze \ COS jesli stan semafora\n zezwoli na to\n\n",getpid()); if( (ktrl=semop(semid, &bs,1))==-1) perror(" blad semop! "); else printf("\n semop zwrocilo wartosc %d\n", ktrl); printf("proces id=%d pisze: COS COS COS COS\n", getpid()); /* to powyższe wypisanie na dowód że proces doczekał się na przyjęcie przez semafor wartości zero */ return 0; } /* koniec funkcji main */
Semafory w przedstawionym powyżej przykładzie proces czeka na wartość zero semafora; poniższy program obniża wartość semafora, może zatem doprowadzić do odblokowania powyższego procesu
Semafory – przykład_3 #include<stdio.h> #include<stdlib.h> //rand() #include<sys/types.h> //key_t #include<sys/ipc.h> //ftok() #include<sys/sem.h> //semget() typedef unsigned short ushort_t; struct sembuf bs = {0, -1, 0};
} sun; //do operacji kontrolnych, semctl Semafory – przykład_3 union semun { int val; struct semid_ds *buf; ushort_t *array; } sun; //do operacji kontrolnych, semctl unsigned short alfa[3];
Semafory – przykład_3 main() { int semid, i; key_t klucz; int ktrl; klucz = ftok(".",110); semid = semget(klucz, 3, 0000 );
perror("Blad otwarcia semafora\n"); return 1; } else Semafory – przykład_3 if(semid == -1) { perror("Blad otwarcia semafora\n"); return 1; } else printf("\n otwarto zbior semaforow o\ ID=%d\n\n",semid);
if ( (ktrl=semop(semid, &bs,1))==-1) perror(" blad semop! "); Semafory – przykład_3 printf(" teraz proces o pid=%d opusci semafor\n\n",getpid()); /* czy opuści aż do zera ? */ if ( (ktrl=semop(semid, &bs,1))==-1) perror(" blad semop! "); else printf("\n semop zwrócilo wartosc %d\n\n", ktrl);
Semafory – przykład_3 sun.array = alfa; semctl(semid, 1, GETALL, sun); /*pobranie wartosci semaforów*/ for(i=0; i<3; ++i) { printf(" wartosc semafora=%d\n", *(alfa+i)); } exit(0); } /* koniec funkcji main */
-- uruchomienie przykład_1 (semafor tworzenie) Semafory zalecane ćwiczenie: -- uruchomienie przykład_1 (semafor tworzenie) -- uruchomienie przykład_2 w tle (proces czeka....) -- kilkakrotne uruchomienie przykład_3 (semafor modyfikacja, wypisanie ustawień, w końcu uaktywni się przykład_2)
potoki (”pipes”, FIFO) sygnały ”shared memory” kolejki wiadomości Podsumowanie potoki (”pipes”, FIFO) sygnały ”shared memory” kolejki wiadomości semafory
Sockets (czyli gniazda) Przy użyciu ”socketów” buduje się dwukierunkową komunikację typu punkt-punkt pomiędzy dwoma procesami. Jest to bardzo giętki proces komunikowania się, jest podstawowoym składnikiem komunikacji pomiędzy procesami (także procesami działającymi na różnych komputerach). ”Socket” musi być identyfikowany przez nazwę, system operacyjny tworzy dla niego jeden (lub więcej) realizujących go procesów. ”Sockets” istnieją w przestrzeni komunikacyjnej. Taka przestrzeń to abstrakcja; ma ona mieć adresującą strukturę (adresującą w sposób jednoznaczny!) i zbiór protokołów, które korzystają z tej przestrzeni. Dwie podstawowe zrealizowane przestrzenie-domeny: UNIX i Internet (np. VMS/VAX praktycznie przestał się liczyć, sieci typu NOVELL także przeszły na TCP/IP)
Sockets (czyli gniazda) dygresja uucp ”UNIX-to-UNIX copy” cu ”connect UNIX”
Sockets Gniazda mogą być oczywiście zrealizowane na pojedynczym systemie. Jeśli użyte gniazdo ma łączyć różne systemy/komputery to trzeba użyć przestrzeni-domeny Internetu (protokoły typu UNIX-to-UNIX praktycznie nie są już używane). krótka dygresja o wspólnym kablu....kiedyś w budynku przy ul. Reymonta 4....
Sockets Rodzaj gniazda (”socketu”) określa jak komunikacja jest wykonywana ”stream socket” tryb połączeniowy. Określa dwustronny, z korekcją błędów przepływ danych, nieduplikowany. Pracuje podobnie jak rozmowa telefoniczna. Typem gniazda jest SOCK_STREAM, używany jest Transmission Transfer Protocol (TCP); czyli dla internetu jest to łącznie TCP/IP. ”datagram socket” tryb bezpołączeniowy. Gniazdo może otrzymać dane w sekwencji innej niż sekwencja wysyłana. Datagramy są duplikowane, jeśli nie zostało otrzymane potwierdzenie, że dotarły. Wymiana informacji jest realizowana jak wysyłanie listów tam i z powrotem. Typem gniazda jest SOCK_DGRAM, używany jest User Datagram Protocol (UDP), czyli dla internetu jest to łącznie UDP/IP.
Sockets int socket(int domain, int type, int protocol) Funkcja tworzy gniazdo w wybranej domenie(PF_INET, PF_UNIX) o określonym type (SOCK_STREAM lub SOCK_DGRAM). Jeśli protokól nie jest podany, system operacyjny sam dobierze protokół obsługujący daną domenę i dany typ gniazda. Funkcja zwraca deskryptor do procesu obsługującego gniazdo (”socket handler”). Inny proces nie może zidentyfikować gniazda dopóki do gniazda nie zostanie przywiązany adres. Procesy mogą komunikować się przez gniazda z przypisanymi adresami: w Internecie gniazdo z przypisanym adresem to inaczej port.
Sockets man socket podaje jeszcze np. : PF_UNIX,PF_LOCAL Local communication PF_INET IPv4 Internet protocols PF_IPX IPX - Novell protocols PF_X25 ITU-T X.25 / ISO-8208 protocol PF_AX25 Amateur radio AX.25 protocol PF_APPLETALK Appletalk
Sockets int bind(int s, struct sockaddr *name, int namelen) funkcja przywiązuje adres do gniazda (ten adres to ścieżka do pewnego pliku który można zobaczyć jako jeden z plików używając komendy ls –l lub adres internetowy. Adres ten jest zamieszczony w strukturze struct sockaddr s to deskryptor zwrócony przez socket() namelen to długość struktury struct sockaddr
srwxr-xr-x 1 rudy users 0 Jan 21 16:22 mojegniazdo Sockets ls –l mojegniazdo srwxr-xr-x 1 rudy users 0 Jan 21 16:22 mojegniazdo
Sockets Gniazdo typu ”przestrzeń UNIX” #include <sys/un.h> int bind (sd, (struct sockaddr *) &addr, length); Gniazdo typu ”przestrzeń Internet” #include <netinet/in.h> w przypadku gniazd typu ”przestrzeń UNIX” użycie bind() powoduje utworzenie gniazda jako widocznego przez np. komendę ls zbioru; można użyc unlink() czy rm() aby gniazdo usunąć.
Stream sockets Użycie gniazda jest zwykle niesymetryczne. Jeden proces działa jako serwer, drugi jako klient. Serwer używa bind() aby przywiązać adres do gniazda. Następnie (dla gniazda SOCK_STREAM) serwer woła funkcję listen(int s, int backlog) , której parametr backlog określa jak wiele jednocześnie usiłowań połączenia z gniazdem może być przyjętych do kolejki (nadmiarowe zostaną odrzucone). Parametr s to deskryptor zwrócony przez socket(). Proces-serwer blokuje się teraz, czeka aż pojawi się jakaś komunikacja na gnieździe.
Stream sockets Proces-klient inicjalizuje połączenie do gniazda utworzonego przez proces-serwer używając funkcji int connect(int s, struct sockaddr *name, int namelen) ; W przypadku przestrzeni-domeny UNIX: connect (sd, (struct sockaddr_un *)&server, length) ; W przypadku przestrzeni-domeny Internet: connect (sd, (struct sockaddr_in *)&server, length) ;
Stream sockets Teraz proces-serwer akceptuje połączenie, woła funkcje accept() która zwraca nowy deskryptor gniazda, na użytek tylko tego jednego połączenia. Proces-serwer może mieć jedocześnie wiecej niż jedno aktywne połączenie SOCK-STREAM. int accept(int s, struct sockaddr *addr, int *addrlen) addr i addrlen są wskaźnikami do obiektów modyfikowanych przezaccept(). Struktura wskazywana przez addr jest wypełniana informacjami o łączącym się procesie, tak jak jest to znane warstwie komunikacyjnej protokołu. *addrlen zwraca wielkość struktury na która wskazuje addr. Można podać addrlen równe NULL, wtedy nic nie jest wypełniane podczas wykonania accept().
Stream sockets Istnieje wiele funkcji które można wykorzystać do czytania i pisania po połączeniu się przez gniazdo typu SOCK_STREAM. write(), read(), send(), recv(). Można również używać np.. buforowanych instrukcji WE/WY, po użyciu fdopen. SOCK_STREAM zamyka się przez close().
Datagram sockets można używać np. send() oraz recv(). Natomiast nie używa się accept() oraz listen().
/* Wspolpracuje z klient1.c */ #include <sys/types.h> Program serwer1.c /* Wspolpracuje z klient1.c */ #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <stdio.h> #define NSTRS 3 #define ADDRESS ”mojegniazdo" /* adres */
Program serwer1.c char *strs[NSTRS] = { ”SERWER to pierwszy wiersz.\n", „SERWER to drugi wiersz.\n", „SERWER to trzeci wiersz.\n" };
Program serwer1.c int main() { char c; FILE *fp; int fromlen; register int i, s, ns, len; struct sockaddr_un saun, fsaun; /* W ”UNIX space-domain” */ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { perror("server: socket"); exit(1); }
Program serwer1.c /* Stworz adres */ saun.sun_family = AF_UNIX; strcpy(saun.sun_path, ADDRESS); unlink(ADDRESS); /* dla pewności zniszcz gniazdo */
Program serwer1.c len = sizeof(saun.sun_family) + strlen(saun.sun_path); /* przywiazanie adresu */ if (bind(s,(struct sockaddr*) &saun, len) < 0) { perror("server: bind"); exit(1); }
Program serwer1.c /* nadsluchiwanie */ if (listen(s, 5) < 0) { perror("server: listen"); exit(1); } /* akceptowanie */ if ((ns = accept(s, (struct sockaddr*) &fsaun, &fromlen)) < 0) { perror("server: accept");
/* użycie fdopen() */ Program serwer1.c fp = fdopen(ns, "r"); /* przeslanie kilku wierszy do klienta */ for (i = 0; i < NSTRS; i++) send(ns, strs[i], strlen(strs[i]), 0);
/* Teraz czytanie kilku wierszy od klienta */ Program serwer1.c /* Teraz czytanie kilku wierszy od klienta */ for (i = 0; i < NSTRS; i++) { while ((c = fgetc(fp)) != EOF) { putchar(c); if (c == '\n') break; }
/* oczywiście można by czytać od klienta używając Program serwer1.c /* oczywiście można by czytać od klienta używając int recv(int s, void *buf, size_t len, int flags); np. recv(s, bufor, 10000,0) gdzie bufor[] to zdefiniowana dodatkowa macierz typu char patrz man 2 recv */ /* zakonczenie polaczenia */ close(s); exit(0); }
proponowane ćwiczenie: uruchomienie powyższego programu np. w tle, server1.c proponowane ćwiczenie: uruchomienie powyższego programu np. w tle, (utworzy się ”mojegniazdo”) a następnie uruchomienie programu poniższego
Program klient1.c #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <stdio.h> #define NSTRS 3 /* liczba wierszy przesyłanych */ #define ADDRESS ”mojegniazdo" /* adres typu UNIX */
Program klient1.c char *strs[NSTRS] = { ”To pierwszy wiersz od klienta.\n”, ”To drugi wiersz od klienta.\n”, ”To trzeci wiersz od klienta.\n” };
Program klient1.c int main() { char c; FILE *fp; register int i, s, len; struct sockaddr_un saun; /* otworz gniazdo do pracy; typ UNIX */ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { perror("client: socket"); exit(1); }
Program klient1.c /* utworz adres do którego się dolaczymy */ saun.sun_family = AF_UNIX; strcpy(saun.sun_path, ADDRESS); len = sizeof(saun.sun_family) + strlen(saun.sun_path); /* len = sizeof(saun) */
Program klient1.c if (connect(s, &saun, len) < 0) { perror("client: connect"); exit(1); } /* zamiast używać recv() do czytania, użyjemy getc(), wcześniej musimy użyć fdopen aby mieć FILE * fp */ fp = fdopen(s, "r");
Program klient1.c /* czytanie tego co przesyła serwer */ for (i = 0; i < NSTRS; i++) { while ((c = fgetc(fp)) != EOF) { putchar(c); if (c == '\n') break; }
/* teraz przesylanie DO SERWERA */ Program klient1.c /* teraz przesylanie DO SERWERA */ for (i = 0; i < NSTRS; i++) send(s, strs[i], strlen(strs[i]), 0); /* zamykanie */ close(s); exit(0); }
socket p poniższy przykład będzie dotyczył przesyłania przez gniazdo z jednego komputera na inny komputer. na pewnym komputerze proces utworzy gniazdo, nada mu ADRES i będzie czekał...
Program serwer2.c #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <stdio.h> #include <netinet/in.h> #define NSTRS 3 /* ilosc wierszy */
Program serwer2.c main() { char c; FILE *fp; int fromlen; register int i, s, ns, len; struct sockaddr_in saun, fsaun;
Program serwer2.c /* utworzenie gniazda typ Internet */ if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) { perror("server: socket"); exit(1); }
Program serwer2.c /* utworzenie adresu; tu adres to adres TEGO KOMPUTERA */ saun.sin_family = AF_INET; saun.sin_port = htons( (uint16_t) 10000 ); /* numer portu */ saun.sin_addr.s_addr = htonl (INADDR_ANY);
Program serwer2.c /* przywiązanie adresu do gniazda */ if (bind(s,(struct sockaddr *) &saun, sizeof(saun)) < 0) { perror("server: bind"); exit(1); }
Program serwer2.c /* sluchanie na gnieździe (”listen on socket”) */ if (listen(s, 5) < 0) { perror("server: listen"); exit(1); } /* akceptowanie przychodzącego do gniazda połączenia */ if ((ns = accept(s, &fsaun, &fromlen)) < 0) { perror("server: accept");
Program serwer2.c /* do czytania będzie wykorzystywane getc() zamiast recv() */ fp = fdopen(ns, "r"); for (i = 0; i < NSTRS; i++) { while ((c = fgetc(fp)) != EOF) { putchar(c); if (c == '\n') break; }
Program serwer2.c /* dalsze czytanie, nieco inaczej wykorzystywane */ /* for (i = 0; i < NSTRS; i++) */ for (;;) /* pętla nieskończona */ {ns = accept(s, &fsaun, &fromlen); fp = fdopen(ns, "r"); while ((c = fgetc(fp)) != EOF) { putchar(c); printf("%%"); } printf("\n byl KONIEC PLIKU ! \n"); close(s); exit(0); } /* koniec main */
htonl, htons, ntohl, ntohs konwertują wartości pomiędzy ”host order” oraz ” network byte order” #include <netinet/in.h> uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort); uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort);
htonl, htons, ntohl, ntohs www.princeton.edu/~kazad/resources/cs/endian.htm Big endian machine: It assumes that the first byte it reads is the biggest Little endian machine: It assumes that the first byte it reads is the littlest. short int: Big endian machine 256 * byte 0 + byte 1 Little endian machine 256 * byte 1 + byte 0
htonl, htons, ntohl, ntohs duże systemy komputerowe mainframe IBM, HONYWELL stacje robocze – SUN, HP, także komputery z LINUX’em, DEC Alpha, VAX, PDP
Program klient2.c #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <stdio.h> #include <netinet/in.h> #define NSTRS 3 /* no. of strings */
Program klient2.c int main() { char c; FILE *fp; int adres; register int i, s, len; struct sockaddr_in saun; /* utwórz gniazdo ”INTERNET space-domain” */ if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) { perror("client: socket"); exit(1); }
Program klient2.c /* utworzenie adresu */ saun.sin_family = AF_INET; saun.sin_port = htons( (uint16_t) 10000); /* to numer portu */ /* saun.sin_addr.s_addr = htonl(INADDR_ANY); */ /* dla adresu IP a.b.c.d, np. 149.156.2.30 */ adres=149*pow(16,6) + 156*pow(16,4) + 2*pow(16,2)+ 32; saun.sin_addr.s_addr = htonl( adres ); /* dolaczenie do 149.156.2.32 saun.sin_addr.s_addr = htonl( 0x959c0220); */
Program klient2.c /* teraz proba podlaczenia się ”do adresu”; serwer w tej chwili nadsluchuje listen() */ if (connect(s, (struct sockaddr *) &saun, sizeof(saun)) < 0) { perror("client: connect"); exit(1); }
Program klient2.c /* nastepuje wyslanie kilku wierszy do serwera */ for (i = 0; i < NSTRS; i++) { send(s, strs[i], strlen(strs[i]), 0); sleep(1); } /* zakończenie */ close(s); exit(0);
połączenie z wykorzystaniem SOCK_DGRAM w przykladach serwer2.c, klient2.c wystarczy zamienić SOCK_STREAM SOCK_DGRAM, oraz w serwer2.c usunąć listen() i accept()
Język C podsumowanie Struktura programu w języku C Zmienne, Stałe Operacje arytmetyczne Operatory logiczne Priorytety operatorów Instrukcje warunkowe (if, ?: , switch) Pętle (for, while, do-while, instrukcje break i continue) Macierze i łańcuchy znakowe (także macierze wielowymiarowe)
Język C podsumowanie /* Alokuje pamiec na macierz n*n */ double **matrixalloc(int n) { int i; double ** bufor; bufor = malloc(n*sizeof(double *)); for(i=0; i<n; i++) bufor[i] = malloc(n*sizeof(double)); return bufor; } /* koniec */ .... double **alfa; alfa = matrixalloc(10);
Język C podsumowanie Funkcje, prototypy funkcji Struktury, unie Rzutowanie na typ Klasy pamięci zmiennych i funkcji Zasięg zmiennej, zasięg funkcji Wskaźniki, macierze, funkcje Dynamiczna alokacja pamięci (malloc,calloc, sizeof, free) Argumenty wiersza wywołania programu Operatory arytmetyczne, logiczne Operatory bitowe, pola bitowe
Język C podsumowanie Preprocesor języka C (makra) Funkcje wejścia/wyjścia(buforowane, niebuforowane, formatowane, bezformatowe) Typ enum Instrukcja typedef Kwalifikatory const, volatile Czytanie deklaracji obiektów w języku C Przykłady (sortowanie, kompresja, struktury danych, IPC itp.)
Język C podsumowanie ....tego nie było... biblioteka ncurses libncurses.a web.cs.mun.ca/~rod/ncurses/ncurses.html
Język C podsumowanie javascript www.w3schools.com/js/default.asp (operatory i pętle jak w C)
Język C podsumowanie PHP www.w3schools.com/php/default.asp (operatory, pętle jak w C)
Język C podsumowanie C++ Sposób zapisywania deklaracji obiektów w C++ jest identyczny jak w języku C. W C++ są klasy i dziedziczenie, czego nie ma w C, ale np. struktury w C++ to z definicji klasa, w której przez domniemanie wszystkie składniki są publiczne. struktura w C jest od razu struktura w C++ różnica: struktura w C++ może mieć funkcje składowe !!
Internet
Internet
Internet