Il Client oscuro
come scrivere un TCP Client in C
Gambol: Dammi una ragione per non dire ai miei uomini di staccarti la testa. Jocker: Ti va bene un trucchetto di magia? Adesso questa matita la faccio sparire!
![]() |
| …con questa matita vi scriverò un post sui Client in C… |
Come si intuisce dal titolo questa volta è il turno del TCP Client (o Socket Client, fa lo stesso). Spero che tutti sappiate cos’è, se no vi consiglio una utile lettura con tanto di esempio (ma il mio esempio è meglio!), così non perdo tempo e posso passare direttamente al codice. Eccolo!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#define MYBUFSIZE 1024
int main(int argc, char *argv[])
{
// test argomenti
if (argc != 3) {
// errore args
printf("%s: numero argomenti errato\n", argv[0]);
printf("uso: %s host port [i.e.: %s 127.0.0.1 8888]\n", argv[0], argv[0]);
return EXIT_FAILURE;
}
// crea un socket
int my_socket;
if ((my_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
// errore socket()
fprintf(stderr, "%s: non posso creare il socket (%s)\n", argv[0], strerror(errno));
return EXIT_FAILURE;
}
// prepara la struttura sockaddr_in per il server remoto
struct sockaddr_in server; // (remoto) server socket info
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET; // set address family
server.sin_addr.s_addr = inet_addr(argv[1]); // set server address
server.sin_port = htons(atoi(argv[2])); // set port number del server
// connessione al server remoto
if (connect(my_socket, (struct sockaddr *)&server, sizeof(server)) < 0) {
// errore connect()
fprintf(stderr, "%s: errore connect (%s)\n", argv[0], strerror(errno));
close(my_socket);
return EXIT_FAILURE;
}
// loop di comunicazione col server remoto
for (;;) {
// compone messaggio per il server remoto
char my_msg[MYBUFSIZE];
printf("Scrivi un messaggio per il Server remoto: ");
scanf("%s", my_msg);
// send messaggio al server remoto
if (send(my_socket, my_msg, strlen(my_msg), 0) < 0) {
// errore send()
fprintf(stderr, "%s: errore send (%s)\n", argv[0], strerror(errno));
close(my_socket);
return EXIT_FAILURE;
}
// riceve una risposta dal server remoto
memset(my_msg, 0, MYBUFSIZE);
if (recv(my_socket, my_msg, MYBUFSIZE, 0) < 0) {
// errore recv()
fprintf(stderr, "%s: errore recv (%s)\n", argv[0], strerror(errno));
close(my_socket);
return EXIT_FAILURE;
}
// mostra la risposta
printf("%s: risposta Server: %s\n", argv[0], my_msg);
}
// 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 TCP Client:
- socket() – crea un socket
- prepara la struttura sockaddr_in per il server remoto
- connect() – connessione al server remoto
- send() + recv() – loop di comunicazione col server remoto
ovviamente esistono varianti di questa struttura, ma questa è quella classica. In quest’esempio, che ho scritto e testato appositamente per il blog (beh, in realtà ho adattato/modificato ad uso blog un po’ di codice che ho scritto per lavoro, non è certo il primo TCP Client che scrivo!), nel loop di comunicazione c’è anche la lettura della risposta del Server, così chiudiamo il cerchio con il post precedente e possiamo testare sul serio una conversazione Client/Server.
Per quanto riguarda il flusso e lo stile del main() valgono le note elencate nel post sul Server. Per testarlo è sufficiente aprire due terminali (UNIX o Linux, ovviamente), e avviare in uno il Server e nell’altro il Client; se proviamo in una macchina sola il Client deve, come è logico, collegarsi al Server su localhost. Per l’argomento port si può usare un numero qualsiasi scelto tra quelli non riservati (e bisogna usare lo stesso port per Client e Server!) Il risultato sarà il seguente:
terminale 1 (Server):
aldo@mylinux:~/blogtest$ ./tcpserver 8888 ./tcpserver: attesa connessioni entranti... ./tcpserver: ricevuto messaggio dal sock 4: pippo ./tcpserver: ricevuto messaggio dal sock 4: pluto ./tcpserver: client disconnesso
terminale 2 (Client):
aldo@mylinux:~/blogtest$ ./tcpclient 127.0.0.1 8888 Scrivi un messaggio per il Server remoto: pippo ./tcpclient: risposta Server: mi hai scritto: pippo Scrivi un messaggio per il Server remoto: pluto ./tcpclient: risposta Server: mi hai scritto: pluto Scrivi un messaggio per il Server remoto: ^C
Come si nota il Client e il Server si parlano e quando il Client si scollega (con un brutale Ctrl-C) il Server se ne accorge. Missione compiuta!
Ecco, con questo post abbiamo completato la presentazione, rapida e concisa, del codice per TCP Server e Client in C (con Berkeley Sockets). Come ho accennato nell’articolo precedente questa è una presentazione propedeutica al vero obbiettivo della trattazione: scrivere TCP Server e Client sicuri in C usando OpenSSL. Lo vedremo presto su questi schermi…
Ciao e al prossimo post!

