fork()
string
do reprezentacji binarnej.string
.socket(int domain, int type, int protocol)
bind(int sockfd, struct sockaddr *my_addr, int addrlen)
socket(2)
i bind(2)
, zwrócić uwagę na parametry jakie przyjmują i wartości jakie zwracają.socket(2)
bind(2)
listen(2)
accept(2)
connect(2)
connect(int sockfd, struct sockaddr *serv_addr, int addrlen)
sockfd
- deskryptor gniazdaserv_addr
- adres hosta docelowego, który możemy otrzymać przy pomocy funckji getaddrinfo
addrlen
- długość adresu, najczęściej podaje się wartość addrinfo::ai_addrlen
sockfd
do komunikowania się z serwerem.connect
ponieważ to zdalny klient będzie jej używał do połączenia się z naszym serwerem.listen(int sockfd, int backlog)
sockfd
- deskryptor gniazda. Nasłuchiwanie będzie się odbywać zgodnie z parametrami opisywanymi przez deskryptor.backlog
- maksymalna liczba połączeń oczekujących na akceptaję.accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
accept(2)
jako wartość zwraca nowy deskryptor gniazda który służy do komunikacji z akceptowanym połączeniem.write(2)
, read(2)
send(2)
, recv(2)
które oferują dodatkową konfigurację.close(2)
close(3)
z funkcją shutdown(3)
.exec {deskryptor-pliku}<>/dev/tcp/{host}/{port}
exec 3<>/dev/tcp/www.google.pl/80
#!/bin/bash ### # Połącz się ze stroną internetową i pobierz zawartość strony głównej ### exec 3<>/dev/tcp/www.google.pl/80 echo -e "GET / HTTP/1.1\nHost: www.google.pl\nConnection: close\n\n" >&3 cat <&3
#!/bin/bash ### # Pobierz aktualny czas z serwera NTP ### cat </dev/tcp/time.nist.gov/13
#!/bin/bash ### # Skaner portów (sprawdza które porty są otwarte). # Jako argument wywołania podaj adres serwera, który chcesz przeskanować, # np. ./port-scanner.sh localhost ### host=$1 port_first=1 port_last=65535 for ((port=$port_first; port<=$port_last; port++)) do # echo "Skanowanie portu $port..." timeout 1 bash -c "(echo >/dev/tcp/$host/$port) >/dev/null 2>&1" && echo "$port otwarty!" done
Przeglądnąć artykuł: Beej's Guide to Network Programming
Skompilować i przetestować omówione w nim programy, w tym:
client.c + server.c (uwaga na nr portu!)
listener.c + talker.c (uwaga na nr portu!)
Kompilacja:
gcc -Wall -o server server.c
#include <stdio.h> #include <errno.h> #include <netdb.h> /* 4 gethostbyname, hostent structure */ #include <unistd.h> /* 4 exit */ #include <netinet/in.h> /* 4 ntohn */ int main(int argc, char *argv[]) { int i,j; struct hostent *he; if (argc != 2) { fprintf(stderr,"usage: %s hostname\n", argv[0]); return 1; } if ((he = gethostbyname(argv[1])) == NULL) { fprintf(stderr, "gethostbyname error\n"); return 1; } /* host info: */ printf("\nHost name: %s", he->h_name); printf("\nAliases:"); for(i=0;he->h_aliases[i] != NULL;++i) printf("\n%d. %s", i+1, he->h_aliases[i]); if(he->h_addrtype == AF_INET) printf("\nAddres type: IPv4"); if(he->h_addrtype == AF_INET6) printf("\nAddres type: IPv6"); printf("\nAddress length: %d bytes", he->h_length); printf("\nAddresses:"); for(j=0;j<he->h_length;++j) { printf("%d", (uint8_t)he->h_addr[j]); if(j < (he->h_length-1)) printf("."); } printf("\n"); return 0; }
www.yahoo.com
oraz innych wybranych adresów symbolicznych.gethostbyname
i w zależności od tego wyświetlają odpowiedni komunikat.Poniżej przedstawiony jest kod programu server.c
/* ** server.c -- a stream socket server demo */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/wait.h> #include <signal.h> #define MYPORT 3490 // the port users will be connecting to #define BACKLOG 10 // how many pending connections queue will hold void sigchld_handler(int s) { while(waitpid(-1, NULL, WNOHANG) > 0); } int main(void) { int sockfd, new_fd; // listen on sock_fd, new connection on new_fd struct sockaddr_in my_addr; // my address information struct sockaddr_in their_addr; // connector's address information socklen_t sin_size; struct sigaction sa; int yes=1; if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1); } if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { perror("setsockopt"); exit(1); } my_addr.sin_family = AF_INET; // host byte order my_addr.sin_port = htons(MYPORT); // short, network byte order my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero); if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof my_addr) == -1) { perror("bind"); exit(1); } if (listen(sockfd, BACKLOG) == -1) { perror("listen"); exit(1); } sa.sa_handler = sigchld_handler; // reap all dead processes sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; if (sigaction(SIGCHLD, &sa, NULL) == -1) { perror("sigaction"); exit(1); } sin_size = sizeof their_addr; if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) { perror("accept"); } printf("server: got connection from %s\n",inet_ntoa(their_addr.sin_addr)); if (send(new_fd, "Hello, world!\n", 14, 0) == -1) perror("send"); sleep(5); // just for observing easily that the server cannot serve a few clients concurrently close(new_fd); return 0; }
$ telnet remotehostname XXX
gdzie remotehostname
jest nazwą komputera, na którym uruchomiono serwer (localhost
, jeżeli to ta sama maszyna), a XXX
numerem przypisanego do niego portu.
fork()
do tworzenia procesów potomnych - każdy proces potomny będzie obsługiwał jednego klienta.