1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
| //
// Serveur réseau mode tcp
// Programme destiné à écouter un client via une connexion mode tcp
// Usage: prog port
//
#include <sys/types.h> // Types prédéfinis "c"
#include <sys/socket.h> // Généralités sockets
#include <sys/param.h> // Paramètres et limites système
#include <arpa/inet.h> // Adresses format "arpanet"
#include <signal.h> // Signaux de communication
#include <netdb.h> // Gestion network database
#include <stdio.h> // I/O fichiers classiques
#include <string.h> // Gestion chaines de caractères
#include <stdlib.h> // Librairie standard Unix
#include <unistd.h> // Standards Unix
#include <errno.h> // Erreurs système
#include "socket_tcp.h" // Outils communs client et serveur
// Structure de travail socket
typedef struct {
int sk_connect; // Socket de connexion
int sk_dialog; // Socket de dialogue
} t_socket; // Type créé
// Fonctions diverses
int init_socket(unsigned short); // Initialisation socket
int client(t_socket*); // Gestion client
int dialogue(int); // Dialogue avec le client
int nslookup(struct sockaddr_in *, char*); // Conversion adresse en nom
// Programme principal
int main(
int argc, // Nbre arguments
char *argv[]) // Ptr arguments
{
// Déclaration des variables
char hostname[MAXHOSTNAMELEN + 1]; // Nom machine locale
t_socket sock; // Socket
// Si le port n'est pas fourni
if (argc <= 1) {
fprintf(stderr, "ligne %u - Pas de port\n", __LINE__);
return -1;
}
// Récuperation nom machine locale (juste pour l'exemple)
if (gethostname(hostname, MAXHOSTNAMELEN) != 0)
fprintf(stderr, "ligne %u - gethostname(%s) - %s\n", __LINE__, hostname, strerror(errno));
printf("gethostname='%s'\n", hostname);
// Détournement du signal émis à la mort du fils (il ne reste pas zombie)
signal(SIGCHLD, SIG_IGN);
// Initialisation socket de connexion
if ((sock.sk_connect=init_socket(argc > 1 ?atoi(argv[1]) :0)) < 0) {
fprintf(stderr, "ligne %u - init_socket() - %s\n", __LINE__, strerror(errno));
return errno;
}
printf("Socket de connexion (%d) initialisée\n", sock.sk_connect);
// Ecoute de la ligne
if (listen(sock.sk_connect, 1) < 0) {
fprintf(stderr, "ligne %u - listen() - %s\n", __LINE__, strerror(errno));
return errno;
}
printf("Socket de connexion (%d) en écoute\n", sock.sk_connect);
// Attente permanente
fputc('\n', stdout);
while (1) {
printf("ppid=%u, pid=%u, socket=%d, attente entrée...\n", getppid(), getpid(), sock.sk_connect);
// Attente connexion client
if (client(&sock) < 0) {
fprintf(stderr, "ligne %u - client() - %s\n", __LINE__, strerror(errno));
continue;
}
}
// Pas de sortie de programme - Boucle infinie
// Fermeture socket et fin théorique du programme (pour être propre)
close(sock.sk_connect);
return 0;
}
// Initialisation socket
int init_socket(
unsigned short port) // Port (éventuel)
{
// Déclaration des variables
struct sockaddr_in adr_serveur; // Adresse socket serveur
int sock; // Socket de connexion
// Création socket
printf("port demandé=%hu\n", port);
if ((sock=socket(AF_INET, SOCK_STREAM, 0)) < 0) {
fprintf(stderr, "ligne %u - socket() - %s\n", __LINE__, strerror(errno));
return -2;
}
printf("Socket de connexion (%d) créée\n", sock);
// Remplissage adresse socket
memset(&adr_serveur, 0, sizeof(struct sockaddr_in));
adr_serveur.sin_family=AF_INET;
adr_serveur.sin_port=htons(port);
adr_serveur.sin_addr.s_addr=INADDR_ANY;
// Identification socket/réseau
if (bind(sock, (struct sockaddr*)&adr_serveur, sizeof(struct sockaddr_in)) < 0) {
fprintf(stderr, "ligne %u - bind() - %s\n", __LINE__, strerror(errno));
return -3;
}
printf("Socket de connexion (%d) identifiée sur le réseau\n", sock);
// Renvoi socket créée
return sock;
}
// Gestion du client
int client(
t_socket *sock) // Socket de communication
{
// Déclaration des variables
int pid; // Process créé
struct sockaddr_in adr_client; // Adresse socket client
socklen_t len_adr; // Taille adresse
char lookup[MAXHOSTNAMELEN + 1024 + 1]; // Correspondance adresse/nom
// Attente connexion client
len_adr=sizeof(struct sockaddr_in);
if ((sock->sk_dialog=accept(sock->sk_connect, (struct sockaddr*)&adr_client, &len_adr)) < 0) {
fprintf(stderr, "ligne %u - accept() - %s\n", __LINE__, strerror(errno));
return -1;
}
// Client connecté
if (nslookup(&adr_client, lookup) < 0)
fprintf(stderr, "ligne %u - nslookup() - %s\n", __LINE__, strerror(errno));
printf("ppid=%d, pid=%d, socket=%d - Entrée émise (dialogue=%d, adr=%s)\n", getppid(), getpid(), sock->sk_connect, sock->sk_dialog, lookup);
// Duplication du process (ne pas oublier de fflusher les flux standards)
fflush(stdout);
fflush(stderr);
switch (pid=fork()) {
case -1: // Erreur de fork
close(sock->sk_connect);
close(sock->sk_dialog);
fprintf(stderr, "ligne %u - fork() - %s\n", __LINE__, strerror(errno));
return -2;
case 0: // Fils
// Fermeture socket de connexion (inutilisée)
close(sock->sk_connect);
// Dialogue avec le client
if (dialogue(sock->sk_dialog) < 0) {
fprintf(stderr, "ligne %u - dialogue() - %s\n", __LINE__, strerror(errno));
exit(errno);
}
// Fin du fils
close(sock->sk_dialog);
printf("\tppid=%d, pid=%d, socket=%d - Entrée raccrochée\n", getppid(), getpid(), sock->sk_dialog);
exit(0);
default: // Père
close(sock->sk_dialog);
}
// Fin fonction
return 0;
}
// Dialogue avec le client
int dialogue(
int sock) // Socket de communication
{
// Déclaration des variables
int sz_read; // Nbre octets lus
char buf[SZ_BUF]; // Buffer texte
char *pt; // Pointeur chaine
// Lecture en boucle sur la socket
while ((sz_read=read(sock, buf, SZ_BUF)) > 0) {
// Par précaution, le buffer reçu est transformé en chaine
buf[sz_read]='\0';
// Suppression du caractère '\n' éventuel
if ((pt=strchr(buf, '\n')) != NULL) *pt='\0';
// Mémorisation chaine contient "EOT" (optimisation)
pt=strcmp(buf, "EOT") != 0 ?buf :NULL;
// Affichage chaine reçue
printf("\tppid=%u, pid=%u, socket=%d - Le serveur a lu %d [%s]%s\n", getppid(), getpid(), sock, sz_read, buf, pt != NULL ?"" :" => Fin de communication");
// Si la chaine contient "EOT"
if (pt == NULL) break;
}
// Si l'arrêt de la lecture est dû à une erreur
if (sz_read < 0) {
fprintf(stderr, "ligne %u - read() - %s\n", __LINE__, strerror(errno));
return -1;
}
// Fin fonction
printf("\tppid=%u, pid=%u, socket=%d - Client terminé\n", getppid(), getpid(), sock);
return 0;
}
// Conversion adresse en nom
int nslookup(
struct sockaddr_in *adr, // Adresse à convertir
char *lookup) // Correspondance adresse/nom
{
// Déclaration des variables
char *adr_ascii; // Adresse client mode ascii
struct hostent *host_info; // Informations host
// Transformation adresse net en ascii
if ((adr_ascii=inet_ntoa(adr->sin_addr)) == NULL) {
fprintf(stderr, "ligne %u - inet_ntoa() - %s\n", __LINE__, strerror(errno));
strcpy(lookup, "?");
return -1;
}
// Récupération informations sur host par son adresse
if ((host_info=gethostbyaddr(&adr->sin_addr.s_addr, sizeof(struct in_addr), AF_INET)) == NULL) {
fprintf(stderr, "ligne %u - gethostbyaddr() - %s\n", __LINE__, strerror(errno));
sprintf(lookup, "%s (?)", adr_ascii);
return -2;
}
sprintf(lookup, "%s (%s)", adr_ascii, host_info->h_name);
return 0;
} |
Partager