I read()
のselect()を使ってクライアントとFIFOからread()を行うと同時に、select()
はFIFOからのデータを認識させます。現時点では、データがFIFOに書き込まれると、selectはすべてのデータをクライアントに書き込みますが、 "ready-to-read"のように戻ります。したがって、次の読み取り値は-1
とerrno == EAGAIN
に設定されます。それはfdmaxに達するまでこれを行います。しかし、それは大丈夫です。クライアントからサーバに接続されたクライアントのC
しかし、なぜ私はEAGAIN
を得続けますか?これを処理するにはより良い方法がありますか?またはこれは適切な方法ですか?
注:私はO_RDWR|O_NONBLOCK
を渡しているので、FIFOだけでなくクライアントによってもデータが送信されるようにします。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>
#define PORT "9034"
int main(void) {
fd_set master, read_fds;
int fdmax, listener, newfd, sbytes, yes=1, i, j, rv;
struct sockaddr_storage remoteaddr; // client address
socklen_t addrlen;
char buf[256] = {0}, remoteIP[INET6_ADDRSTRLEN];
struct addrinfo hints, *ai;
FD_ZERO(&master);
FD_ZERO(&read_fds);
int fifo;
if ((mkfifo("/tmp/fifo", 0666)) < 0)
perror(strerror(errno));
if ((fifo = open("/tmp/fifo", O_RDWR|O_NONBLOCK)) < 0)
perror(strerror(errno));
// get us a socket and bind it
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
rv = getaddrinfo(NULL, PORT, &hints, &ai);
listener = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
bind(listener, ai->ai_addr, ai->ai_addrlen);
freeaddrinfo(ai);
listen(listener, 10);
FD_SET (fifo, &master);
FD_SET(listener, &master);
fdmax = listener;
for (;;) {
read_fds = master;
if (select(fdmax + 1, &read_fds, NULL, NULL, NULL) == -1) exit(4);
for (i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) {
if (i == listener) {
addrlen = sizeof remoteaddr;
newfd = accept(listener, (struct sockaddr *) & remoteaddr, & addrlen);
FD_SET(newfd, & master);
if (newfd > fdmax)
fdmax = newfd;
} else if (i != fifo) {
recv(i, buf, sizeof buf, 0);
}
}
if (FD_ISSET(fifo, &read_fds)) {
sbytes = read (fifo, buf, sizeof (buf));
if (sbytes == -1 && errno == EAGAIN)
continue;
for(j = 0; j <= fdmax; j++) {
// send to everyone!
if (FD_ISSET(j, &master)) {
if (j != listener && j != i && j != fifo) {
if (send(j, buf, sbytes, 0) == -1) {
perror("send");
}
}
}
}
}
}
}
return 0;
}
'fdmax = listener;'は疑わしいです。実際にはどちらが大きいかを評価する必要があります。それぞれの 'recv()'の結果をチェックする必要があります。あなたはソケットケースでそれをやっていません。具体的には、ゼロになる可能性があります。つまり、ピアが切断されているため、ソケットを閉じて 'read_fds'と' master'からソケットを削除する必要があります。 – EJP
ありがとうございます。簡単にするために、私は多くの小切手を取り除いた。私はそれを追加することを確認します。 –
'fdmax'と同様に、助けがあれば、[this code of code](https://github.com/boazsegev/c-server-tools/blob/b27548898dea4b0e8fb42b439dd7f50d7c0e7073/src/lib-server)を見ることができます。 c#L1729-L1749)は、プロセスの最大ファイル制限をチェックします(OSのハード制限まで最大化しようとします)。 – Myst