- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
作为一个学校项目,我正在实现一个 IRC 服务器,我今天一直被这个问题所困扰。我的服务器使用 select 来选择哪个客户端正在发送数据,然后它从该用户读取一个命令(命令是\r\n 分隔的),解析它并在传递给下一个用户之前执行它。用户可以像这样一次发送多个命令:
"command1\r\ncommand2\r\n"
如果发生这种情况,我希望第一个命令被执行,第二个命令保留在流中,以便在下一次 select() 调用时可以读取它。 (这样,每个用户每个“回合”只执行一个命令)。为此,我为每个客户端设置了一个 FILE *stream,只要连接就保持打开状态。
这非常有效(如果我发送上面指定的双命令,这两个命令会一个接一个地执行)。
问题是在那之后,select() 继续告诉我套接字中有东西要读取(fd 返回 1 的 FD_ISSET),所以我的接收函数被调用为那个 fd 和 getline()它失败了(没有设置 errno)并且它永远这样循环。
我不明白为什么 select 仍然认为套接字中有东西要读取以及为什么 getline 失败而不是阻塞。
有什么想法吗?
编辑:我不允许在这个项目中使用非阻塞套接字或 fork()
“主”循环:
while (g_run_server)
{
fd_max = g_socket_fd;
FD_ZERO(fds);
FD_SET(g_socket_fd, fds);
tmp = users;
while (tmp)
{
FD_SET(tmp->fd, fds);
fd_max = (tmp->fd > fd_max ? tmp->fd : fd_max);
tmp = tmp->next;
}
if (select(fd_max + 1, &fds, NULL, NULL, NULL) < 0)
break;
if (FD_ISSET(g_socket_fd, &fds))
accept_new_user(&hdl, &users);
handle_clients(&hdl, &fds);
}
处理和读取客户端输入的函数:
static bool recv_and_execute(t_handle *hdl)
{
char *raw;
size_t len;
len = 0;
raw = NULL;
if (!hdl->sender->stream &&
(hdl->sender->stream = fdopen(dup(hdl->sender->fd), "r")) == NULL)
return (false);
if (getline(&raw, &len, hdl->sender->stream) != -1)
{
printf("Received \"%s\"\n", raw);
parse_cmd(hdl, raw);
exec_cmd(hdl);
}
else
printf("Getline failed %s\n", strerror(errno));
free(raw);
return (true);
}
int handle_clients(t_handle *hdl, fd_set *fds)
{
t_user *tmp;
tmp = *hdl->users;
while (tmp)
{
if (FD_ISSET(tmp->fd, fds))
{
printf("fd %d is ready to be read\n", tmp->fd);
hdl->sender = tmp;
recv_and_execute(hdl);
FD_CLR(tmp->fd, fds);
tmp = tmp->next;
if (hdl->sender->status == DEAD)
del_user(hdl->users, hdl->sender);
}
else
tmp = tmp->next;
}
return (0);
}
这是当我连接一个客户端并发送“USER foo\r\nUSER no bo dy :wa\r\n”时的输出:
fd 4 is ready to be read
Received "NICK foo
"
[DEBUG] Executing "NICK" with params "foo" "(null)" "(null)" "(null)"
[INFO] Nickname successfully changed.
fd 4 is ready to be read
Received "USER no bo dy :wa
"
[DEBUG] Executing "USER" with params "no" "bo" "dy" ":wa"
[INFO] User registered.
fd 4 is ready to be read
Getline failed Success
fd 4 is ready to be read
Getline failed Success
fd 4 is ready to be read
Getline failed Success
fd 4 is ready to be read
Getline failed Success
fd 4 is ready to be read
Getline failed Success
continue like this....
编辑:我根据 alk 的评论编辑了我的接收函数:
static bool recv_and_execute(t_handle *hdl)
{
char *raw;
size_t len;
ssize_t nread;
len = 0;
raw = NULL;
if (!hdl->sender->stream &&
(hdl->sender->stream = fdopen(dup(hdl->sender->fd), "r")) == NULL)
return (false);
errno = 0;
if ((nread = getline(&raw, &len, hdl->sender->stream)) > 0)
{
printf("Received \"%s\"\n", raw);
parse_cmd(hdl, raw);
exec_cmd(hdl);
}
else if (errno != 0)
printf("getline failed %s\n", strerror(errno));
else {
printf("EOF reached\n");
fclose(hdl->sender->stream);
hdl->sender->stream = NULL;
}
printf("nread = %zd\n", nread);
free(raw);
return (true);
}
所以这一次,当到达 EOF(getline 返回 -1)时,我关闭流并将其设置为 NULL,以便下次在套接字 fd 上选择查找数据时重新打开。但即使当我关闭流时,选择仍然检测到有可用数据并且无限循环继续:/
fd 4 is ready to be read
Received "NICK foo^M
"
nread = 10
fd 4 is ready to be read
Received "USER no bo dy :wa^M
"
nread = 19
fd 4 is ready to be read
EOF reached
nread = -1
fd 4 is ready to be read
EOF reached
nread = -1
fd 4 is ready to be read
EOF reached
nread = -1
and so on...
最佳答案
我很确定您使用的 select
有误。我向您展示了一个关于如何使用它的简单代码示例(我不处理很多错误),您可以根据需要对其进行编辑。
/*
* If you read at man select bugs you can see
* that select could return that someone is
* ready but it isn't true
*/
int fd_c;
fd_set rdset;
fd_set set; /*That's the mask you'll use when new requests arrive*/
FD_ZERO(&set); /*Clears the mask*/
FD_SET(g_socket_fd,&set); /*Set the listening socket as ready*/
while(g_run_server){
/*
* YOU MUST INITIALIZATE IT EVERY LOOP
* read @ man select
*/
rdset = set;
if(select((fd_num_max+1),(&rdset),NULL,NULL,NULL) < 0){
perror("Failed on select\n");
exit(EXIT_FAILURE);
}
/*You go through the ready clients in the rdset*/
for(fd=0;fd<=fd_num_max;fd++) {
if(FD_ISSET(fd,&rdset)) { /*If the bit is set*/
if(fd == fd_skt) { /*If it's a new client*/
/*You can handle the new client here or delegete it to someone*/
fd_c=accept(fd_skt,NULL,0); /*File descriptor of new client*/
FD_SET(fd_c,&set);
if(fd_c > fd_num_max) fd_num_max = fd_c;
}else { /*If it's a request from an existing client*/
/*You can handle the new request here or delegete it to someone*/
FD_SET(fd,&set);
}
}
}
}
您还应该这样修改 static bool recv_and_execute(t_handle *hdl)
:
errno = 0;
if ((nread = getline(&raw, &len, hdl->sender->stream)) != -1){
printf("Received \"%s\"\n", raw);
parse_cmd(hdl, raw);
exec_cmd(hdl);
}else{
if( errno == 0){
printf("EOF reached\n");
fclose(hdl->sender->stream);
hdl->sender->stream = NULL;
}else{
printf("getline failed %s\n", strerror(errno));
exit(EXIT_FAILURE); /*You must handle it in some way, exiting or doing something*/
}
}
关于C 套接字 : FD_ISSET return true with no data waiting,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44245597/
这个问题在这里已经有了答案: Why in Python does "0, 0 == (0, 0)" equal "(0, False)"? (7 个回答) 去年关闭。 代码片段 1: a = Tru
Integer i = 127; Integer j = 127; System.out.println(i == j); System.out.println(i.equals(j)); Integ
我试图用 Python 进行类似下面的代码的比较,但对产生的输出感到困惑。 谁能解释为什么输出是这样的? >>> True, True == True, True (True, True, True)
我们的下拉值是动态的 010100。 你能帮我将这些值转换为 true、false 吗? Offer的值是10100,Reject的值是10111。所以这些需要转换成 10100 = true,fal
我正在测试,如果用户在页面顶部显示一种货币“EUR”和另一种货币“GBP”,那么我期望包含文本“EUR”和页面下方还存在另一个包含文本“GBP”的链接。它包含在一个名为 "nav-tabs au-ta
如何检查数组的所有元素是真值还是假值。 因为以下内容似乎没有做到这一点:_.all([true, true, true], true); 它返回:false? 最佳答案 您应该重新阅读_.every(
C#:我有一个如下所示的字符串变量: string a = "(true and true) or (true or false)"; 这可以是任何东西,它可以变得更复杂,比如: string b
ruby : true == true == true syntax error, unexpected tEQ 对比JavaScript: true == true == true // => tr
这个问题已经有答案了: Equality of truthy and falsy values (JavaScript) (3 个回答) Which equals operator (== vs ==
为什么 R 中的 TRUE == "TRUE" 是 TRUE? R 中是否有与 === 等效的内容? 更新: 这些都返回FALSE: TRUE == "True" TRUE == "true" TRU
简单的查询,可能不可能,但我知道那里有一些聪明的人:) 给定一个 bool 参数,我希望定义我的 where 子句来限制特定列的输出 - 或不执行任何操作。 因此,给定参数@bit = 1,结果将是:
编写 Excel 公式时,将值设置为 true、“true”还是 true() 是否有区别? 换句话来说,以下哪一个是最好的?还是要看具体情况? if (A1 = 1, true, false) if
如果我们评估这个:TRUE AND TRUE,为什么会这样? 'yes' : 'no' 等于 TRUE 但不等于 yes 何时评估:(TRUE AND TRUE) ? 'yes' : 'no' 等于
这个问题在这里已经有了答案: Behaviour of and operator in javascript [duplicate] (1 个回答) 关闭 7 年前。 如题所说,我不太明白为什么(t
我有一个包含 FromDate 、 ToDate 、 VendorName 和 GoodsName 的表单,一旦一切为真,我需要显示结果 示例: FromDate="11/20/2019"、ToDat
我最近参加了 Java 的入门测试,这个问题让我很困惑。完整的问题是: boolean b1 = true; boolean b2 = false; if (b2 != b1 != b2) S
我有一个模型,我有: ipv4_address = models.IPAddressField(verbose_name=_('ipv4 address'), blank=True, null=Tru
False in [True,True] False in pd.Series([True,True]) 第一行代码返回False第二行代码返回 True! 我想我一定是做错了什么或者遗漏了什么。当我
我可以在 Coq 中证明以下内容吗? Lemma bool_uip (H1 : true = true): H1 = eq_refl true. 即true = true 的所有证明都相同吗? 例如
如果我的理解是正确的,他们做的事情完全一样。为什么有人会使用“for”变体?仅仅是味道吗? 编辑:我想我也在考虑 for (;;)。 最佳答案 for (;;) 通常用于防止编译器警告: while(
我是一名优秀的程序员,十分优秀!