您需要在循环中调用select()
(或更好),在其中传递其参数 an包含侦听套接字描述符和所有连接的客户端套接字描述符。退出时,它会告诉您哪些套接字上有待处理的可读数据。epoll()
readfds
fd_set
select()
如果侦听套接字有待读取的数据,则调用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);