Sockets BSD - Comment utiliser les sockets non bloquant?
Je suis en train d'utiliser la non-blocage des sockets TCP. Le problème, c'est qu'ils sont toujours de blocage. Le code est ci-dessous -
code serveur -
struct sockaddr name;
char buf[80];
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
int main(int agrc, char** argv) {
int sock, new_sd, adrlen; //sock is this socket, new_sd is connection socket
name.sa_family = AF_UNIX;
strcpy(name.sa_data, "127.0.0.1");
adrlen = strlen(name.sa_data) + sizeof(name.sa_family);
//make socket
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
printf("\nBind error %m", errno);
exit(1);
}
//unlink and bind
unlink("127.0.0.1");
if(bind (sock, &name, adrlen) < 0)
printf("\nBind error %m", errno);
//listen
if(listen(sock, 5) < 0)
printf("\nListen error %m", errno);
//accept
new_sd = accept(sock, &name, (socklen_t*)&adrlen);
if( new_sd < 0) {
cout<<"\nserver accept failure "<<errno;
exit(1);
}
//set nonblock
set_nonblock(new_sd);
char* in = new char[80];
std::string out = "Got it";
int numSent;
int numRead;
while( !(in[0] == 'q' && in[1] == 'u' && in[2] == 'i' && in[3] == 't') ) {
//clear in buffer
for(int i=0;i<80;i++)
in[i] = ' ';
cin>>out;
cin.get();
//if we typed something, send it
if(strlen(out.c_str()) > 0) {
numSent = send(new_sd, out.c_str(), strlen(out.c_str()), 0);
cout<<"\n"<<numSent<<" bytes sent";
}
numRead = recv(new_sd, in, 80, 0);
if(numRead > 0)
cout<<"\nData read from client - "<<in;
} //end while
cout<<"\nExiting normally\n";
return 0;
}
code client -
struct sockaddr name;
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
int main(int agrc, char** argv) {
int sock, new_sd, adrlen;
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
printf("\nserver socket failure %m", errno);
exit(1);
}
//stuff for server socket
name.sa_family = AF_UNIX;
strcpy(name.sa_data, "127.0.0.1");
adrlen = strlen(name.sa_data) + sizeof(name.sa_family);
if(connect(sock, &name, adrlen) < 0) {
printf("\nclient connection failure %m", errno);
exit(1);
}
cout<<"\nSuccessful connection\n";
//set nonblock
set_nonblock(sock);
std::string out;
char* in = new char[80];
int numRead;
int numSent;
while(out.compare("quit")) {
//clear in
for(int i=0;i<80;i++)
in[i] = '\0';
numRead = recv(sock, in, 80, 0);
if(numRead > 0)
cout<<"\nData read from server - "<<in;
cout<<"\n";
out.clear();
cin>>out;
cin.get();
//if we typed something, send it
if(strlen(out.c_str())) {
numSent = send(sock, out.c_str(), strlen(out.c_str()), 0);
cout<<"\n"<<numSent<<" bytes sent";
}
} //end while
cout<<"\nExiting normally\n";
return 0;
}
Chaque fois que je le lance, le serveur attend encore pour m'envoyer quelque chose avant de lire et de sortie, ce que le client a envoyé. Je veux que ce soit le serveur ou le client pour être en mesure d'envoyer le message dès que je le taper, et à l'autre de lire et d'éditer le message de l'époque. Je pensais que les sockets non bloquant est la réponse, mais peut-être que je suis juste à faire quelque chose de mal?
Aussi, j'ai été en utilisant un fichier à la place de mon adresse 127.0.0.1 comme la structure sockaddr de données. Si ce n'est pas la façon dont il devrait être correctement utilisé, n'hésitez pas à le dire (il a travaillé la façon dont il a travaillé précédemment avec un fichier alors j'ai continué comme ça).
Toute aide est appréciée.
Vous devez vous connecter pour publier un commentaire.
Eh bien, c'est comment vous l'avez écrit. Vous bloquez sur IO à partir de stdin, et alors, et seulement alors faites-vous envoyer/recevoir.
Aussi, vous êtes à l'aide d'un socket local (AF_UNIX), ce qui crée un fichier spécial dans votre système de fichiers pour la communication interprocessus - ce mécanisme est différent de la propriété intellectuelle, et n'est certainement pas le protocole TCP comme vous l'indiquez dans votre question. Je supposons que vous pouvez nommer le fichier 127.0.0.1, mais qui n'a vraiment pas de sens et qui implique une confusion de votre part, parce que c'est une IP adresse de bouclage. Vous aurez envie d'utiliser AF_INET de la propriété intellectuelle.
Pour un excellent guide de démarrage sur unix réseau, je le recommande http://beej.us/guide/bgnet/
Si vous souhaitez que l'affichage de messages reçus pour être indépendant de votre cin états, soit fork() off un autre processus pour gérer votre réseau IO, ou utiliser un thread séparé.
Vous pourriez être intéressé à select(). À mon avis non bloquant les sockets sont généralement un hack, une bonne utilisation de select() ou poll() est généralement beaucoup mieux de conception et plus souple (et plus portable). essayez
pour plus d'informations.
Approche générale pour un serveur TCP où vous souhaitez gérer plusieurs connexions en même temps:
select(2)
oupoll(2)
lire événementselect(2)
/poll(2)
boucleaccept(2)
EAGAIN
code d'erreur - il n'est pas vraiment une erreur, mais une indication qu'il n'y a pas d'entrée maintenantclose(2)
socket client, le retirer de l'organisation d'une épreuveselect(2)
)Côté Client est un peu plus simple puisque vous n'avez qu'une seule prise. Avancée des applications comme les navigateurs web qui gèrent de nombreux liens souvent non-bloquant
connect(2)
bien.Je pense que vous devez définir la non-block plus tôt (c'est à dire obtenir le support puis le mettre non bloquer)
vérifiez également que le fcntl pour définir elle a effectivement travaillé
Si vous voulez non-blocage i/o, vous souhaitez utiliser, sélectionnez. Vous pouvez le définir à stdin comme l'une des prises, il est à l'écoute, avec les sockets client (juste ajouter un descripteur de fichier 1, qui est l'entrée standard stdin, à la fd_set).
http://beej.us/guide/bgnet/output/html/multipage/advanced.html
Je vous recommande de lire au travers de ce que beej a à dire sur sélectionner. Il semble un peu intimidant, mais c'est vraiment utile et simple à utiliser si vous prenez un peu de temps pour envelopper votre tête autour de lui.