C 我的服务器程序只在第二个请求到达时才响应第一个请求?
我试图通过编写一个服务器-客户机原型程序来学习套接字编程 服务器和客户端都需要能够处理来自stdin的命令,因此我使用select函数 我的问题是,服务器程序被阻止,只有在客户端发送另一个请求后才响应客户端请求 服务器.c 你能给我指一下正确的方向吗?我是否缺少有关发送和接收行为的信息?要使用select作为正确的IO多路复用工具,您需要正确维护FD_设置。由于每次select返回时,FD_集合只包含准备好进行操作的FD,这意味着您必须在每次调用select之前重新装备FD_集合 代码中还有另一个问题,您不能只在循环中的FD_集合中添加新客户机,您需要保存它,然后在开始时重新配置它们 此外,您不需要检查集合中的每个FD,因为select将返回准备进行IO的FD数量 尝试以下更改:C 我的服务器程序只在第二个请求到达时才响应第一个请求?,c,sockets,io,client-server,multiplexing,C,Sockets,Io,Client Server,Multiplexing,我试图通过编写一个服务器-客户机原型程序来学习套接字编程 服务器和客户端都需要能够处理来自stdin的命令,因此我使用select函数 我的问题是,服务器程序被阻止,只有在客户端发送另一个请求后才响应客户端请求 服务器.c 你能给我指一下正确的方向吗?我是否缺少有关发送和接收行为的信息?要使用select作为正确的IO多路复用工具,您需要正确维护FD_设置。由于每次select返回时,FD_集合只包含准备好进行操作的FD,这意味着您必须在每次调用select之前重新装备FD_集合 代码中还有另一
int clients[MAX_CLIENTS] = {0};
int I;
int maxfd;
int server_sock = <the listening fd>;
FD_SET readfds;
int ret;
while(1) {
// Setup SD_SET each time calling select
FD_ZERO(&readfds);
FD_SET(STDIN_FILENO, &readfds);
maxfd = STDIN_FILENO;
FD_SET(server_sock, &readfds);
maxfd = max(maxfd, server_sock);
for (I = 0; I < MAX_CLIENTS; I++) {
if (clients[I] >= 0) {
FD_SET(clients[I], &readfds);
maxfd = max(maxfd, clients[I]);
}
if ((ret = select(maxfd+1,&readfds,NULL,NULL,NULL)) == -1) {
error("Err in select");
}
for(i = 0; i < maxfd && ret; i++, ret--) {
if(FD_ISSET(i, &readfds) {
if (i == listenfd) {
// < add new client to clients array
}
else if (i == STDIN_FILENO) { /* keyboard input */
// < parse server commands >
}
else {
// one of the client is ready
int nread = recv(i,buffer,BUFLEN,0);
if (nread == 0) {
// client is closed, remove I from clients array
continue;
}
process(buffer);
send(i,buffer,BUFLEN,0);
}
}
}
}
最后但并非最不重要的一点是,作为对select的改进,可以在Linux上尝试类似epoll的功能,它可以为您维护状态,这样您就不需要像select那样重新武装所有FD。默认情况下无限期地记住recv块。您可以使用setsockopt设置超时。此外,您需要管理循环中的fd_集数据,而您不需要。。。请注意,Linux声明,由于select修改其文件描述符集,因此如果在循环中使用调用,则必须在每次调用之前重新初始化这些集。如果使用linux,则更喜欢epoll而不是select。如果使用BSD,请选择kqueue而不是select。Windows有重叠的IO,Solaris有evpoll。。。如果您的代码预期在不同的系统上运行,请考虑使用抽象库即LIEBV。祝你好运@Myst我有两个fd_集变量,一个是constantread_fds,另一个是tmpfds,每次都会修改。我忘了在while循环的开头添加read_fds=tmpfds行,my bad。使用select,每次都需要在循环的顶部重建fd_集。如果不希望阻塞,则集合应包含所有文件描述符。除非FD_ISSET说文件描述符已经准备好,否则不要对文件描述符执行任何读写操作,否则会遇到阻塞。这意味着您可能处于这样一种情况,即您已经读取了一些数据,并且希望将其写入。。你还不能。。因此,你需要在做事的顺序上变得聪明。。或者将数据存储在缓冲区中。
while(1)
{
if (select(fdmax + 1, &tmpfds, NULL, NULL, NULL) == -1)
{
error("Err in select");
}
if (FD_ISSET(0,&tmpfds))
{
fgets(buffer, BUFLEN, stdin);
process_request(buffer);
send(serverfd, buffer, BUFLEN, 0);
}
else if (FD_ISSET(serverfd,&tmpfds))
{
recv(serverfd, buffer, BUFLEN, 0);
process_response(buffer);
}
}
int clients[MAX_CLIENTS] = {0};
int I;
int maxfd;
int server_sock = <the listening fd>;
FD_SET readfds;
int ret;
while(1) {
// Setup SD_SET each time calling select
FD_ZERO(&readfds);
FD_SET(STDIN_FILENO, &readfds);
maxfd = STDIN_FILENO;
FD_SET(server_sock, &readfds);
maxfd = max(maxfd, server_sock);
for (I = 0; I < MAX_CLIENTS; I++) {
if (clients[I] >= 0) {
FD_SET(clients[I], &readfds);
maxfd = max(maxfd, clients[I]);
}
if ((ret = select(maxfd+1,&readfds,NULL,NULL,NULL)) == -1) {
error("Err in select");
}
for(i = 0; i < maxfd && ret; i++, ret--) {
if(FD_ISSET(i, &readfds) {
if (i == listenfd) {
// < add new client to clients array
}
else if (i == STDIN_FILENO) { /* keyboard input */
// < parse server commands >
}
else {
// one of the client is ready
int nread = recv(i,buffer,BUFLEN,0);
if (nread == 0) {
// client is closed, remove I from clients array
continue;
}
process(buffer);
send(i,buffer,BUFLEN,0);
}
}
}
}