我们正在写一个客户端和服务器(我认为是)非常简单的网络通信.多个客户端连接到服务器,然后服务器将数据发送回所有其他客户端.
服务器只是位于阻塞select循环中等待流量,当它到来时,将数据发送到其他客户端.这似乎工作得很好.
问题是客户.在阅读时,它有时会想要写一次.
但是,我发现如果我使用:
rv = select(fdmax + 1, &master_list, NULL, NULL, NULL);
Run Code Online (Sandbox Code Playgroud)
我的代码将阻塞,直到有新数据要读取.但有时(异步,来自另一个线程)我将在网络通信线程上写入新数据.所以,我希望我的select定期唤醒,让我检查是否有要写的数据,如:
if (select(....) != -1)
{
if (FD_SET(sockfd, &master_list))
// handle data or disconnect
else
// look for data to write and write() / send() those.
}
Run Code Online (Sandbox Code Playgroud)
我尝试将选择设置为轮询模式(或荒谬的短暂超时):
// master list contains the sockfd from the getaddrinfo/socket/connect seq
struct timeval t;
memset(&t, 0, sizeof t);
rv = select(fdmax + 1, &master_list, NULL, NULL, &t);
Run Code Online (Sandbox Code Playgroud)
但是发现那时客户端永远不会得到任何传入的数据.
我也尝试将socket fd设置为非阻塞,如:
fcntl(sockfd, F_SETFL, O_NONBLOCK);
Run Code Online (Sandbox Code Playgroud)
但这并没有解决问题:
select()没有struct …我有一个Java Thread,它暴露了其他线程想要访问的属性:
class MyThread extends Thread {
private Foo foo;
...
Foo getFoo() {
return foo;
}
...
public void run() {
...
foo = makeTheFoo();
...
}
}
Run Code Online (Sandbox Code Playgroud)
问题是从运行到foo可用时需要很短的时间.呼叫者可以getFoo()在此之前致电并获得null.我宁愿他们只是阻塞,等待,并在初始化发生后获取值.(foo之后永远不会改变.)在它准备好之前它将是几毫秒,所以我对这种方法很满意.
现在,我可以通过这种方式实现这一目标,wait()并且notifyAll()有95%的可能性我会做得对.但我想知道你们都会怎么做; 有没有一个原始人java.util.concurrent会这样做,我错过了?
或者,你会如何构建它?是的,制造foo易变的.是的,在内部锁定上同步Object并将检查放入while循环中,直到它不是null.我错过了什么吗?
几天前,我不得不调查我的应用程序在(显然)处于空闲状态时显示异常高CPU使用率的问题.我将问题跟踪到一个循环,这个循环意味着recvfrom在套接字被设置为O_NONBLOCK-ing 时阻塞一个调用,导致旋转锁定.有两种方法可以解决问题:使用poll或设置套接字阻塞或轮询套接字上的可用数据select.我选择前者因为它更简单.但我想知道为什么任何人会创建一个非阻塞套接字然后单独轮询它.阻塞套接字是否也这样做?使用非阻塞套接字和轮询组合的用例有哪些?在一般情况下它有什么优势吗?
在Java中实现非阻塞套接字的最佳方法是什么?
还是有这样的事情?我有一个通过套接字与服务器通信的程序,但是如果数据/连接出现问题,我不希望套接字调用阻塞/导致延迟.
如果一种方法必须是阻止方法,我是否正确地认为如果我遗漏throws InterruptedException,我犯了一个错误?
简而言之:
throws InterruptedException另外一种常规方法.throws InterruptedException.那是对的吗?
此答案指示如何转换java.util.concurrent.Future为scala.concurrent.Future,同时管理阻塞将发生的位置:
import java.util.concurrent.{Future => JFuture}
import scala.concurrent.{Future => SFuture}
val jfuture: JFuture[T] = ???
val promise = Promise[T]()
new Thread(
new Runnable {
def run() { promise.complete(Try{ jfuture.get }) }
}
).start
val future = promise.future
Run Code Online (Sandbox Code Playgroud)
我的问题与评论中提出的问题相同:
怎么了
future { jfuture.get }?为什么你使用额外的线程与Promise结合?
答案如下:
它会在你的线程拉动中阻止线程.如果您为这样的期货配置了ExecutionContext,那很好,但是默认的ExecutionContext包含与处理器一样多的线程.
我不确定我理解这个解释.重申:
怎么了future { jfuture.get }?在手中创建一个新线程并在那里阻塞时,在未来内部是否阻塞?如果没有,它有什么不同?
我试图更多地了解在Go中各种阻塞/等待操作类型期间在表面下发生的事情.请看以下示例:
otherChan = make(chan int)
t = time.NewTicker(time.Second)
for {
doThings()
// OPTION A: Sleep
time.Sleep(time.Second)
// OPTION B: Blocking ticker
<- t.C
// OPTION C: Select multiple
select {
case <- otherChan:
case <- t.C:
}
}
Run Code Online (Sandbox Code Playgroud)
从低级别的视图(系统调用,cpu调度)这些等待时间有什么区别?
我的理解是time.Sleep让CPU自由执行其他任务,直到指定的时间结束.阻止股票代码是否<- t.C也这样做?处理器是否轮询通道或是否涉及中断?选择中有多个频道会改变什么吗?
换句话说,假设otherChan从未有任何东西投入其中,这三个选项是否会以相同的方式执行,还是会比其他选项的资源密集程度更低?
我想编写自己的抗干扰工具.我不能/不想使用主机或第三方应用程序.使用IPSEC或Windows防火墙时,它只接受IP地址.有
youtube.[264 TLD]
www.youtube.[264 TLD]
subdomains.youtube.[264 TLD]
显然,没有办法获得youtube子域的完整列表.
有人可以想办法以某种方式获取所有youtube ip地址并在ip级别阻止它们而不是使用暴力子域ping?
我有一个简单的sysfs设备属性,显示在我的sysfs目录下,并在调用时read返回一个kernelspace变量的值.我想调用poll此属性以允许我的用户空间线程阻塞,直到属性显示的值发生更改.
我的问题是poll似乎没有阻止我的属性 - POLLPRI即使属性显示的值没有改变,它仍然会返回.实际上,我sysfs_notify在内核模块中根本没有调用,但用户空间调用poll仍然没有阻塞.
也许我应该检查比其他东西返回值POLLPRI-但根据文档中的Linux内核,sysfs_poll应该返回POLLERR|POLLPRI:
/* ... When the content changes (assuming the
* manager for the kobject supports notification), poll will
* return POLLERR|POLLPRI ...
*/
Run Code Online (Sandbox Code Playgroud)
有什么我忘了做的事poll吗?
device属性位于:/ sys/class/vilhelm/foo/blah.
我加载了一个名为foo的内核模块,它注册了一个设备,并创建了一个类和这个设备属性.
名为bar的用户空间应用程序生成一个调用poll设备属性的线程,检查POLLPRI.
poll返回正数,POLLPRI则返回.fopen和fscan从设备属性文件中读取值.在Rust中生成阻塞IO的线程似乎是一个常见的习惯用法,因此您可以使用非阻塞通道:
use std::sync::mpsc::channel;
use std::thread;
use std::net::TcpListener;
fn main() {
let (accept_tx, accept_rx) = channel();
let listener_thread = thread::spawn(move || {
let listener = TcpListener::bind(":::0").unwrap();
for client in listener.incoming() {
if let Err(_) = accept_tx.send(client.unwrap()) {
break;
}
}
});
}
Run Code Online (Sandbox Code Playgroud)
问题是,重新加入这样的线程取决于生成的线程"意识到"通道的接收端已经被丢弃(即,调用send(..)返回Err(_)):
drop(accept_rx);
listener_thread.join(); // blocks until listener thread reaches accept_tx.send(..)
Run Code Online (Sandbox Code Playgroud)
你可以为TcpListeners 创建虚拟连接,并TcpStream通过克隆关闭s,但这些似乎是清理这些线程的真正hacky方法,而且就目前而言,我甚至不知道在读取时触发线程阻塞的黑客攻击从stdin加入.
我怎样才能清理这些线程,或者我的架构是错的?