Ich spiele mit Epoll unter Linux zum ersten Mal und sehe ein seltsames Verhalten. Wenn ich mich mit einem Client mit einem Socket verbinde, sehe ich zwei Ereignisse, die von epoll_wait auf der Serverseite ausgegeben werden. Wenn ich beim zweiten Versuch accept anrufe, bekomme ich einen "temporary unavailable" -Fehler.Sehen zwei akzeptieren Ereignisse auf epoll
Hier ist der einfache Client-Code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
const char* msg = "friendly ping";
int main(int argc, char** argv) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <socket>\n", argv[0]);
exit(-1);
}
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
perror("socket");
exit(-1);
}
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, argv[1], sizeof(addr.sun_path) - 1);
if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
perror("Error connecting");
exit(-1);
}
write(sock, msg, strlen(msg));
close(sock);
return 0;
}
Der Server-Code ist der folgende:
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
const int kMaxEvents = 100;
const char *kSocketFile = "dummy_socket";
void MakeNonBlocking(int fd) {
int flags, s;
flags = fcntl (fd, F_GETFL, 0);
if (flags == -1) {
perror ("fcntl");
exit(-1);
}
flags |= O_NONBLOCK;
s = fcntl (fd, F_SETFL, flags);
if (s == -1) {
perror ("fcntl");
exit(-1);
}
}
void AcceptConnections(int sock, int epoll_fd) {
struct epoll_event event;
event.data.fd = sock;
event.events = EPOLLIN;
int insock = accept(sock, NULL, NULL);
if (insock < 0) {
perror("Error accepting connection");
exit(-1);
}
MakeNonBlocking(insock);
int s = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, insock, &event);
if (s < 0) {
perror("Epoll error adding accepted connection");
exit(-1);
}
printf("Connection processed.\n");
}
int main(void) {
int sock, efd, n;
struct sockaddr_un addr;
struct epoll_event event;
struct epoll_event *events;
char buf[1024];
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("Error creating socket.");
exit(-1);
}
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, kSocketFile, sizeof(addr.sun_path) - 1);
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
perror("Error binding name to socket");
exit(-1);
}
if (listen(sock, SOMAXCONN) < 0) {
perror("Error listening on socket");
exit(-1);
}
MakeNonBlocking(sock);
if ((efd = epoll_create1(0)) < 0) {
perror("Epoll initialization error");
exit(-1);
}
event.data.fd = sock;
event.events = EPOLLIN;
if (epoll_ctl(efd, EPOLL_CTL_ADD, sock, &event) < 0) {
perror("Epoll error adding socket");
exit(-1);
}
events = (struct epoll_event*) calloc(kMaxEvents, sizeof(event));
if (!events) {
perror("Error allocating event buffers");
exit(-1);
}
while(1) {
printf("Calling epoll_wait\n");
if ((n = epoll_wait(efd, events, kMaxEvents, -1)) == -1) {
perror("epoll_wait failure");
exit(-1);
}
for (int i = 0; i < n; ++i) {
printf("Checking event for fd = %d\n", events[i].data.fd);
if (sock == events[i].data.fd) {
AcceptConnections(sock, efd);
continue;
}
int count = read(events[i].data.fd, buf, 100);
if (count == 0) {
close(events[i].data.fd);
}
write(1, buf, count);
}
}
free(events);
close(efd);
close(sock);
unlink(kSocketFile);
return 0;
}
Wenn ich den Server ausgeführt werden und eine Verbindung zum Client erhalte ich:
Calling epoll_wait
Checking event for fd = 3
Connection processed.
Calling epoll_wait
Checking event for fd = 3
Error accepting connection: Resource temporarily unavailable
Mit anderen Worten, ich sehe zwei Ereignisse auf dem hörenden Sockel. Irgendwelche Ideen?
Ich würde gerne das überprüfen, aber ich bekomme den Laufzeitfehler: 'Fehler beim Binden des Namens an den Socket: Operation nicht erlaubt' ... – Myst