Non è un Blog di Cinema questo, neh? |
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <errno.h> #define BACKLOG 10 // per listen() #define MYBUFSIZE 1024 int main(int argc, char *argv[]) { // test argomenti if (argc != 2) { // errore args printf("%s: numero argomenti errato\n", argv[0]); printf("uso: %s port [i.e.: %s 9999]\n", argv[0], argv[0]); return EXIT_FAILURE; } // crea un socket int my_socket; if ((my_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { // errore socket() printf("%s: could not create socket (%s)\n", argv[0], strerror(errno)); return EXIT_FAILURE; } // prepara la struttura sockaddr_in per questo server struct sockaddr_in server; // (local) server socket info server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons(atoi(argv[1])); // bind informazioni del server al socket if (bind(my_socket, (struct sockaddr *)&server, sizeof(server)) < 0) { // errore bind() printf("%s: bind failed (%s)", argv[0], strerror(errno)); return EXIT_FAILURE; } // start ascolto con una coda di max BACKLOG connessioni if (listen(my_socket, BACKLOG) < 0) { // errore listen() printf("%s: listen failed (%s)\n", argv[0], strerror(errno)); return EXIT_FAILURE; } // accetta connessioni da un client entrante printf("%s: attesa connessioni entranti...\n", argv[0]); socklen_t socksize = sizeof(struct sockaddr_in); struct sockaddr_in client; // (remote) client socket info int client_sock; if ((client_sock = accept(my_socket, (struct sockaddr *)&client, &socksize)) < 0) { // errore accept() printf("%s: accept failed (%s)\n", argv[0], strerror(errno)); return EXIT_FAILURE; } // loop di ricezione messaggi dal client int read_size; char client_msg[MYBUFSIZE]; while ((read_size = recv(client_sock, client_msg, MYBUFSIZE, 0)) > 0 ) { // send messaggio di ritorno al client printf("%s: ricevuto messaggio dal sock %d: %s\n", argv[0], client_sock, client_msg); char server_msg[MYBUFSIZE]; sprintf(server_msg, "mi hai scritto: %s", client_msg); write(client_sock, server_msg, strlen(server_msg)); // clear buffer memset(client_msg, 0, MYBUFSIZE); } // loop terminato: test motivo if (read_size < 0) { // errore recv() printf("%s: recv failed\n", argv[0]); return EXIT_FAILURE; } else if (read_size == 0) { // Ok: il client si è disconnesso printf("%s: client disconnected\n", argv[0]); } // esco con Ok return EXIT_SUCCESS; }
Ok, come vedete è ampiamente commentato e quindi è auto-esplicativo, per cui non mi dilungherò sulle singole istruzioni e/o gruppi di istruzioni (leggete i commenti! sono li per quello!), ma aggiungerò, solo, qualche dettaglio strutturale.
la struttura è quella classica e basica di un Socket Server:
- socket() - crea un socket
- prepara la struttura sockaddr_in per questo server
- bind() - bind informazioni del server al socket
- listen() - start ascolto con una coda di max BACKLOG connessioni
- accept() - accetta connessioni da un client entrante
- recv() - loop di ricezione messaggi dal client
Notare, poi, che il main() inizia con un bel test sugli argomenti con eventuale esempio di uso in caso di errore: questo dà la opportuna aria professionale al codice e non dovrebbe mai mancare in una applicazione di questo tipo.
Dal punto di vista strettamente stilistico ho scritto questo codice non rispettando il mio stile preferito (ci sono multipli punti di uscita) ma per un programma quasi-sequenziale come questo non è uno stile disprezzabile, e poi... mi è venuto così! Del resto a suo tempo avevo detto che ci vuole un po' di elasticità, mai essere troppo rigidi.
Un ultimo accenno sulla #define BACKLOG: trovare il valore adatto è un argomento quasi filosofico, per cui vi rimando a una ottima descrizione che ho trovato in linea. Ci rivediamo per il Client e, come sempre, non trattenete il respiro nell'attesa...
Ciao e al prossimo post!
Nessun commento:
Posta un commento