Forum Programmation.c Programmer un client réseau en C

Posté par  .
Étiquettes : aucune
0
2
jan.
2006
Hello !
Voici ce qui m'amène :
nous avons une vieille imprimante bull pr800 dont ne voulons pas nous séparer. Comme les serveurs sont maintenant centralisés, et que celle-ci le peut se connecter que par le biais d'un câble parallèle, j'envisage d'écrire un petit programme en C pour la piloter.
En effet, ce modèle d'imprimante matricielle n'est que partiellement supporté par cups, il me faut donc pouvoir imprimer n'importe quoi dessus, pourvu que ce soit du texte.
Comme ce n'est pas une imprimante ni pcl, ni postscript, pas moyen d'écrire un fichier ppd ou même un filtre pour cups, d'où mon idée initiale :
- brancher cette vieille machine au réseau grâce à un boîtier hp jetdirect (cette partie fonctionne à merveille)
- déclarer cette imprimante comme une file raw sur une socket (actuellement 192.168.0.190:9100) dans cups (ça fonctionne aussi).
- écrire un petit programme en C qui :
1) ouvre une connexion vers cette imrpimante
2) lui envoie les codes escp/2 nécessaires à la configuration demandée
3) Fait un appel système à lp -d pr800 fichier pour envoyer le fichier via cups sur l'imprimante
4) Envoie un caractère de fin de page ^L à l'imprimante pour lui faire comprendre que c'est fini, et se recaler pour la suivante.
Les points 2 et 3 sont acquis, car j'avais déjà fait ça en local en utilisant /dev/lp0.
Pour le point 1, j'ai écrit ce bout de code, qui devrait imprimer un joli A sur ma feuille de papier, mais il ne fonctionne pas et me renvoie systématiquement : "Erreur: Connection refused".
Le code :

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

int main ()
{
int sockfd;
int longueur;
struct sockaddr_in adresse;
int resultat;
char ch='A';
sockfd = socket (AF_INET, SOCK_STREAM, 0);
adresse.sin_family = AF_INET;
adresse.sin_addr.s_addr = inet_addr("192.168.0.190");
adresse.sin_port = 9100;

longueur = sizeof (adresse);
resultat = connect (sockfd, (struct sockaddr *)&adresse, longueur);
if (resultat == -1)
{
perror ("Erreur");
exit (1);
}
write (sockfd, &ch, 1);
close (sockfd);
exit(0);
}

Ce que je ne comprend pas, c'est que si je fais un telnet 192.168.0.190 9100, j'obtiens ce message ;
Trying 192.168.127.190...
Connected to 192.168.127.190.
Escape character is '^]'.

A partir de là, tout caractère tapé au clavier est immédiatement imprimé sur la feuille....
Je ne vois vraiment pas ce qui cloche, ni comment m'en sortir.

Pour le point 4, le soucis, c'est qu'il faut ouvrir la socket quand cups (du moins la commande lp) l'a libéré, et pas avant pour lui envoyer le caractère ^L. Et ça, je ne sais pas comment coder ça.
Merci pour votre aide et vos suggestions.
  • # network byte order

    Posté par  . Évalué à 4.

    Les fonctions de l'api socket attendent que les structures passées en parametres soient remplies en "network byte order" (c'est-à-dire en big-endian), et pas en "host byte order" (sur un x86, little-endian).
    bref, remplace "adresse.sin_port = 9100;" par "adresse.sin_port = htons(9100);" (htons = "host to network, short" convertissant tes "short int" dans la représentation voulue).

    "man byteorder" pour la suite.
    • [^] # Re: network byte order

      Posté par  . Évalué à 2.

      Merci, c'est exactement là que ça clichait...
      Maintenant, il me faut résoudre le point 4....
      Autant avec une ouverture du /dev/lp0 ça me faisait un coredump, autant avec une socket réseau, ça ne fait rien, mais alors rien du tout....
      Comment être sûr de tout envoyer (les séquences d'échappement escp/2, le fichier par le biais de la commande lp, le ^L en fin) ?
      A moins que ce soit plus simple de passer par une lecture et un envoi complet du fichier avec des fread d'un côté et des write de l'autre... A étudier, mais je suis ouvert à toute proposition, tant qu'elle reste en rapport avec mon problème !

      Au fait, rien à voir avec ta réponse, mais je ne vois pas comment éviter de coder en dur l'adresse ip de mon imprimante. Ne puis-je récupérer son adresse depuis les fichiers de conf de cups ?
      Apparement, les fichiers situés dans /etc/cups ne sont pas lisibles par le commun des mortels, alors je ne vois pas trop comment procéder....
  • # Erreur assez classique.

    Posté par  . Évalué à 1.

    Salut, ton erreur est assez classique.
    En fait tu fais un:


    adresse.sin_addr.s_addr = inet_addr("192.168.0.190");


    adresse.sin_addr.s_addr est selon ip(7) un u_int32_t appartenant à une structure de type in_addr.

    La fonction inet_addr(3) quant à elle renvoie directement une structure de type in_addr.
    L'assignation correcte serait donc:


    adresse.sin_addr = inet_addr("192.168.0.190");


    As tu pensé au flag -Wall de gcc qui t'aurait certainement montré cette erreur ?

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.