di creare il socket, metterlo in ascolto di connessioni in arrivo e creare un
processo figlio a cui delegare la gestione di ciascuna connessione. Questa
parte, riportata in \figref{fig:TCPsimpl_serv_code}, è analoga a quella vista
-nel precedente esempio esaminato in \secref{sec:TCPel_cunc_serv}.
+nel precedente esempio esaminato in \secref{sec:TCP_cunc_daytime}.
\begin{figure}[!htb]
- \footnotesize
- \begin{lstlisting}{}
-/* Subroutines declaration */
-void ServEcho(int sockfd);
-/* Program beginning */
-int main(int argc, char *argv[])
-{
- int list_fd, conn_fd;
- pid_t pid;
- struct sockaddr_in serv_add;
- ...
- /* create socket */
- if ( (list_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- perror("Socket creation error");
- exit(-1);
- }
- /* initialize address */
- memset((void *)&serv_add, 0, sizeof(serv_add)); /* clear server address */
- serv_add.sin_family = AF_INET; /* address type is INET */
- serv_add.sin_port = htons(13); /* daytime port is 13 */
- serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */
- /* bind socket */
- if (bind(list_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
- perror("bind error");
- exit(-1);
- }
- /* listen on socket */
- if (listen(list_fd, BACKLOG) < 0 ) {
- perror("listen error");
- exit(-1);
- }
- /* handle echo to client */
- while (1) {
- /* accept connection */
- if ( (conn_fd = accept(list_fd, NULL, NULL)) < 0) {
- perror("accept error");
- exit(-1);
- }
- /* fork to handle connection */
- if ( (pid = fork()) < 0 ){
- perror("fork error");
- exit(-1);
- }
- if (pid == 0) { /* child */
- close(list_fd); /* close listening socket */
- SockEcho(conn_fd); /* handle echo */
- exit(0);
- } else { /* parent */
- close(conn_fd); /* close connected socket */
- }
- }
- /* normal exit, never reached */
- exit(0);
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15.6cm}
+ \includecodesample{listati/ElemEchoTCPServer.c}
+ \end{minipage}
+ \normalsize
\caption{Codice della funzione \code{main} della prima versione del server
per il servizio \texttt{echo}.}
\label{fig:TCPsimpl_serv_code}
La struttura di questa prima versione del server è sostanzialmente identica a
quella dell'esempio citato, ed ad esso si applicano le considerazioni fatte in
-\secref{sec:TCPel_cunc_daytime}. Le uniche differenze rispetto all'esempio in
-\figref{fig:TCPel_serv_code} sono che in questo caso per il socket in ascolto
+\secref{sec:TCP_cunc_daytime}. Le uniche differenze rispetto all'esempio in
+\figref{fig:TCP_serv_code} sono che in questo caso per il socket in ascolto
viene usata la porta 7 e che tutta la gestione della comunicazione è delegata
alla funzione \code{ServEcho}.
% Per ogni connessione viene creato un
all'interno del ciclo (linee \texttt{\small 6--8}). I dati inviati dal client
vengono letti dal socket con una semplice \func{read} (che ritorna solo in
presenza di dati in arrivo), la riscrittura viene invece gestita dalla
-funzione \func{SockWrite} (descritta in \figref{fig:sock_SockWrite_code}) che
+funzione \func{FullWrite} (descritta in \figref{fig:sock_FullWrite_code}) che
si incarica di tenere conto automaticamente della possibilità che non tutti i
dati di cui è richiesta la scrittura vengano trasmessi con una singola
\func{write}.
\begin{figure}[!htb]
- \footnotesize
- \begin{lstlisting}{}
-void ServEcho(int sockfd) {
- char buffer[MAXLINE];
- int nread, nwrite;
-
- /* main loop, reading 0 char means client close connection */
- while ( (nread = read(sockfd, buffer, MAXLINE)) != 0) {
- nwrite = SockWrite(sockfd, buffer, nread);
- }
- return;
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15.6cm}
+ \includecodesample{listati/ServEcho.c}
+ \end{minipage}
+ \normalsize
\caption{Codice della prima versione della funzione \code{ServEcho} per la
gestione del servizio \texttt{echo}.}
\label{fig:TCPsimpl_server_elem_sub}
Il codice del client è riportato in \figref{fig:TCPsimpl_client_elem}, anche
esso ricalca la struttura del precedente client per il servizio
-\texttt{daytime} (vedi \secref{sec:net_cli_sample}) ma, come per il server, lo
+\texttt{daytime} (vedi \secref{sec:TCP_cli_sample}) ma, come per il server, lo
si è diviso in due parti, inserendo la parte relativa alle operazioni
specifiche previste per il protocollo \texttt{echo} in una funzione a parte.
+
\begin{figure}[!htb]
- \footnotesize
- \begin{lstlisting}{}
-int main(int argc, char *argv[])
-{
-/*
- * Variables definition
- */
- int sock_fd, i;
- struct sockaddr_in serv_add;
- ...
- /* create socket */
- if ( (sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- perror("Socket creation error");
- return -1;
- }
- /* initialize address */
- memset((void *) &serv_add, 0, sizeof(serv_add)); /* clear server address */
- serv_add.sin_family = AF_INET; /* address type is INET */
- serv_add.sin_port = htons(7); /* echo port is 7 */
- /* build address using inet_pton */
- if ( (inet_pton(AF_INET, argv[optind], &serv_add.sin_addr)) <= 0) {
- perror("Address creation error");
- return -1;
- }
- /* extablish connection */
- if (connect(sock_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
- perror("Connection error");
- return -1;
- }
- /* read daytime from server */
- ClientEcho(stdin, sock_fd);
- /* normal exit */
- return 0;
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15.6 cm}
+ \includecodesample{listati/EchoServerWrong.c}
+ \end{minipage}
+ \normalsize
\caption{Codice della prima versione del client \texttt{echo}.}
\label{fig:TCPsimpl_client_elem}
\end{figure}
La funzione \code{main} si occupa della creazione del socket e della
connessione (linee \texttt{\small 10--27}) secondo la stessa modalità spiegata
-in \secref{sec:net_cli_sample}, il client si connette sulla porta 7
+in \secref{sec:TCP_cli_sample}, il client si connette sulla porta 7
all'indirizzo specificato dalla linea di comando (a cui si è aggiunta una
elementare gestione delle opzioni non riportata in figura).
ricevuto in risposta dal server.
\begin{figure}[!htb]
- \footnotesize
- \begin{lstlisting}{}
-void ClientEcho(FILE * filein, int socket)
-{
- char sendbuff[MAXLINE], recvbuff[MAXLINE];
- int nread;
- while (fgets(sendbuff, MAXLINE, filein) != NULL) {
- SockWrite(socket, sendbuff, strlen(sendbuff));
- nread = SockRead(socket, recvbuff, strlen(sendbuff));
- recvbuff[nread] = 0;
- fputs(recvbuff, stdout);
- }
- return;
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15.6cm}
+ \includecodesample{listati/ClientEcho.c}
+ \end{minipage}
+ \normalsize
\caption{Codice della prima versione della funzione \texttt{ClientEcho} per
la gestione del servizio \texttt{echo}.}
\label{fig:TCPsimpl_client_echo_sub}
presi dallo \file{stdin} usando la funzione \func{fgets} che legge una
linea di testo (terminata da un \texttt{CR} e fino al massimo di
\const{MAXLINE} caratteri) e la salva sul buffer di invio, la funzione
-\func{SockWrite} (\texttt{\small 3}) scrive detti dati sul socket (gestendo
+\func{FullWrite} (\texttt{\small 3}) scrive detti dati sul socket (gestendo
l'invio multiplo qualora una singola \func{write} non basti, come spiegato
in \secref{sec:sock_io_behav}).
-I dati che vengono riletti indietro con una \func{SockRead} sul buffer di
+I dati che vengono riletti indietro con una \func{FullRead} sul buffer di
ricezione e viene inserita la terminazione della stringa (\texttt{\small
7--8}) e per poter usare la funzione \func{fputs} per scriverli su
\file{stdout}.
server a cui questo risponderà con un ACK. A questo punto il client verrà a
trovarsi nello stato \texttt{FIN\_WAIT\_2} ed il server nello stato
\texttt{CLOSE\_WAIT} (si riveda quanto spiegato in
- \secref{sec:TCPel_conn_term}).
+ \secref{sec:TCP_conn_term}).
\item quando il server riceve il FIN la \func{read} del processo figlio che
gestisce la connessione ritorna restituendo 0 causando così l'uscita dal
ciclo e il ritorno di \code{ServEcho}, a questo punto il processo figlio
\figref{fig:sig_Signal_code}, per installare il semplice gestore che
riceve i segnali dei processi figli terminati già visto in
\figref{fig:sig_sigchld_handl}; aggiungendo il seguente codice:
-\begin{lstlisting}{}
- ...
- /* install SIGCHLD handler */
- Signal(SIGCHLD, sigchld_hand); /* establish handler */
- /* create socket */
- ...
-\end{lstlisting}
-
+\includecodesnip{listati/sigchildhand.c}
\noindent
all'esempio illustrato in \figref{fig:TCPsimpl_serv_code}, e linkando il tutto
alla funzione \code{sigchld\_hand}, si risolverà completamente il problema