Spis treści

Programowanie połączeń sieciowych

DO PRZYGOTOWANIA

WPROWADZENIE

Network Byte Order

getaddrinfo

Obsługa adresów IPv4 oraz IPv6

Gniazda

Podstawowe funkcje systemowe:

Połączenie

Nasłuchiwanie

Wysyłanie/odbieranie danych

Zamknięcie połączenia

ĆWICZENIA

Sockety w Bashu

webpage.sh
#!/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
timeserver.sh
#!/bin/bash
 
###
# Pobierz aktualny czas z serwera NTP
### 
 
cat </dev/tcp/time.nist.gov/13
port-scanner.sh
#!/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

Programowanie gniazd

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

gethostbyname

  1. Proszę przeanalizować, skompilować i uruchomić program:
    gethostbyname-demo.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;
    }
  2. Sprawdzić działanie programu dla www.yahoo.com oraz innych wybranych adresów symbolicznych.
  3. Dopisać instrukcje, które szczegółowo sprawdzają typ błędu funkcji gethostbyname i w zależności od tego wyświetlają odpowiedni komunikat.
  4. Zmodyfikować tak program aby wyświetlał wszystkie adresy IP odnoszące się do podanego adresu.

Serwer

Poniżej przedstawiony jest kod programu server.c

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;
}

25.1 Komunikator

25.2 Eternal vigilance

25.3 Obsługa wielu klientów

Dla poszerzenia wiedzy