gpt4 book ai didi

c - 我的服务器程序只在第二个请求到达时才回答第一个请求?

转载 作者:太空宇宙 更新时间:2023-11-04 03:30:37 25 4
gpt4 key购买 nike

我正在尝试通过编写服务器-客户端原型(prototype)程序来学习套接字编程。

服务器和客户端都需要能够处理来自 stdin 的命令,所以我使用了 select 函数。

我的问题是 server 程序被阻塞,只有在客户端发送另一个请求后才响应客户端请求。

server.c

while(1)
{
if (select(maxfd + 1, &tmpfds, NULL, NULL, NULL) == -1)
{
error("Err in select");
}
for (i = 0; i < maxfd; i++)
{
if(FD_ISSET(i,&tmpfds)
{
if (i == listenfd)
{
< add new client to list >
}
else if (i == 0)
{
< parse server commands >
}
else
{
/* This is where I think my problem is */
recv(i, buffer, BUFLEN, 0);
process(buffer);
send(i, buffer, BUFLEN, 0);
}
}
}

客户端.c

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);
}
}

你能给我指明正确的方向吗?我是否遗漏了一些有关 sendrecv 行为的信息?

最佳答案

要将select 用作正确的IO 多路复用工具,您需要正确维护FD_SET。由于每次 select 返回时,FD_SET 只包含准备好操作的 fds,这意味着您必须在调用之前重新设置 FD_SET 每次选择

你的代码还有一个问题,你不能在循环中的 FD_SET 中添加新的客户端,你需要保存它然后在开始时重新装备它们。

此外,您不需要检查集合中的每个 FD,因为 select 将返回准备好进行 IO 的 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 一样重新装备所有 fds。

关于c - 我的服务器程序只在第二个请求到达时才回答第一个请求?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36904068/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com