0

我有一个程序可以打印我发送的文件的内容:

struct addrinfo hints;
struct addrinfo *serverInfo;

memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;

getaddrinfo(NULL, PUERTO, &hints, &serverInfo);
//socket para escuchar
int listenningSocket;
listenningSocket = socket(serverInfo->ai_family, serverInfo->ai_socktype, serverInfo->ai_protocol);
bind(listenningSocket,serverInfo->ai_addr, serverInfo->ai_addrlen);
freeaddrinfo(serverInfo);

listen(listenningSocket, BACKLOG);
struct sockaddr_in addr;
socklen_t addrlen = sizeof(addr);
int socketCliente = accept(listenningSocket, (struct sockaddr *) &addr, &addrlen);
char package[PACKAGESIZE];
int status = 1;

printf("\nCliente conectado. Esperando mensajes:\n");
printf("\nEl contenido del script es: \n");

while (status != 0) {
    status = recv(socketCliente, (void*) package, PACKAGESIZE, 0);
    if (status != 0) printf("%s", package);
}
close(socketCliente);
close(listenningSocket);

但我希望这个程序监听我想打印的其他东西。所以我需要循环socket,监听socket。我知道我需要该select()功能,但我不知道如何将它用于我的代码。

4

1 回答 1

0

您需要在循环中调用select()(或更好),在其中传递其参数 an包含侦听套接字描述符和所有连接的客户端套接字描述符。退出时,它会告诉您哪些套接字上有待处理的可读数据。epoll()readfdsfd_setselect()

如果侦听套接字有待读取的数据,则调用accept()它,如果成功,则将返回的套接字描述符添加到某处的跟踪列表中,以便您可以将其包含在对select().

如果任何其他套接字有待读取的数据,请调用recv()它们并根据需要对它们的数据进行操作。如果recv()在任何给定套接字上返回 -1 或 0,close()则该套接字描述符并将其从跟踪列表中删除,以便在后续调用select().

话虽如此,您的所有套接字调用都缺少足够的错误处理。它们中的任何一个都可能失败,而您不会知道这一点尤其重要,recv()因为您可以正确检测和清理任何断开/丢失的客户端连接。

此外,您假设recv()始终返回以空字符结尾的字符串,但事实并非如此。客户端可以发送一个以空字符结尾的字符串,但recv()不能保证在一次读取中读取整个以空字符结尾的字符串。您必须recv()在循环中调用,缓冲任何接收到的数据,直到您实际收到空终止符,然后继续处理完成的字符串。

试试类似这样的(伪代码让你根据需要填写客户端跟踪列表的实现细节):

struct addrinfo hints;
struct addrinfo *serverInfo;

memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;

if (getaddrinfo(NULL, PUERTO, &hints, &serverInfo) < 0) {
    // TODO: error handling...
    return -1;
}

//socket para escuchar
int listenningSocket = socket(serverInfo->ai_family, serverInfo->ai_socktype, serverInfo->ai_protocol);
if (listenningSocket < 0) {
    // TODO: error handling...
    freeaddrinfo(serverInfo);
    return -1;
}

if (bind(listenningSocket, serverInfo->ai_addr, serverInfo->ai_addrlen) < 0) {
    // TODO: error handling...
    freeaddrinfo(serverInfo);
    close(listenningSocket);
    return -1;
}

freeaddrinfo(serverInfo);

if (listen(listenningSocket, BACKLOG) < 0) {
    // TODO: error handling...
    close(listenningSocket);
    return -1;
}

struct sockaddr_in addr;
socklen_t addrlen;
int socketCliente, maxfd, status;
char package[PACKAGESIZE];
char *str;
struct timeval timeout;

someList clients; // TODO: for you to decide the implementation of...

while (!someStopCondition) { // TODO: for you to decide the implementation of...

    fd_set rfd;
    FD_ZERO(&rfd);

    FD_SET(listenningSocket, &rfd);
    maxfd = listenningSocket;

    for (each fd in clients) { // TODO: for you to decide the implementation of...
        FD_SET(fd, &rfd);
        if (fd > maxfd) {
            maxfd = fd;
        }
    }

    // TODO: for you to decide on...
    timeout.tv_sec = ...;
    timeout.tv_usec = ...;

    status = select(maxfd + 1, &rds, NULL, NULL, &timeout);
    if (status < 0) {
        // TODO: error handling...
        break;
    }

    if (status == 0) {
        // TODO: do other things as needed...
        continue;
    }

    if (FD_ISSET(listenningSocket, &rds)) {
        addrlen = sizeof(addr);
        socketCliente = accept(listenningSocket, (struct sockaddr *) &addr, &addrlen);
        if (socketCliente < 0) {
            // TODO: error handling...
        }
        else if (!addToList(&clients, socketCliente)) { // TODO: for you to decide the implementation of...
            // TODO: error handling...
            close(socketCliente);
        } else {
            printf("\nCliente conectado. Esperando mensajes:\n");
        }
    }

    for (each fd in clients) { // TODO: for you to decide the implementation of...
        if (FD_ISSET(fd, &rfd)) {
            status = recv(fd, package, PACKAGESIZE, 0);
            if (status <= 0) {
                close(socketCliente);
                removeFromList(&clients, fd); // TODO: for you to decide the implementation of...
                continue;
            }

            // TODO: for you to decide the implementation of...
            addToEndOfClientBuffer(fd, package, status);
            while ((str = getNullTerminatedStringFromClientBuffer(fd)) != NULL) {
                printf("\nEl contenido del script es: %s\n", str);
                removeFromFrontOfClientBuffer(fd, strlen(str)+1);
            }
        }
    }
}

// TODO: for you to decide the implementation of...
for (each fd in clients) {
    close(fd);
}
clearList(&clients);

close(listenningSocket);
于 2020-08-19T22:52:18.073 回答