Non-blocking BSD socket connections

本文探讨了非阻塞BSD套接字连接的处理方式,特别是当使用connect()返回EINPROGRESS或EWOULDBLOCK时,如何通过不同的方法检查连接是否成功或失败,包括使用getsockopt获取so_error、尝试读写操作进行错误滑落、使用getpeername等。

Non-blocking BSD socket connections

Situation: You set up a non-blocking socket and do a connect() that returns -1/EINPROGRESS or -1/EWOULDBLOCK. You select() the socket for writability. This returns as soon as the connection succeeds or fails. (Exception: Under some old versions of Ultrix, select() wouldn't notice failure before the 75-second timeout.)

Question: What do you do after select() returns writability? Did the connection fail? If so, how did it fail?

If the connection failed, the reason is hidden away inside something called so_error in the socket. Modern systems let you see so_error with getsockopt(,,SO_ERROR,,), but this isn't portable---in fact, getsockopt() can crash old systems. A different way to see so_error is through error slippage: any attempt to read or write data on the socket will return -1/so_error.

Sometimes you have data to immediately write to the connection. Then you can just write() the data. If connect() failed, the failure will be reported by write(), usually with the right connect() errno. This is the solution I supplied for IRC in 1990. Unfortunately, on some systems, under some circumstances, write() will substitute EPIPE for the old errno, so you lose information.

Another possibility is read(fd,&ch,0). If connect() succeeded, you get a 0 return value, except under Solaris, where you get -1/EAGAIN. If connect() failed, you should get the right errno through error slippage. Fatal flaw: under Linux, you will always get 0.

Another possibility is read(fd,&ch,1), but this leads to programming difficulties, since a character may in fact have arrived. Everything that reads the socket has to know about your pre-buffered character.

Another possibility is recv(,,,MSG_PEEK). Unfortunately, the recv() code for stream sockets was, historically, completely untested and a massive source of bugs. I'd steer clear of this.

Another possibility is to select() for readability. But this is wrong, because the connect() may have succeeded and data may have arrived before you had time to do a select().

Another possibility is getpeername(). If the socket is connected, getpeername() will return 0. If the socket is not connected, getpeername() will return ENOTCONN, and read(fd,&ch,1) will produce the right errno through error slippage. This is a combination of suggestions from Douglas C. Schmidt and Ken Keys.

Another possibility is a second connect(). This seems to be a strictly worse solution than getpeername(): it doubles network traffic if the connection failed (with some TCP stacks), and doesn't improve reliability. Ken Keys mentions that this works with SOCKS.


在UVM(Universal Verification Methodology)中实现非阻塞(non-blocking)驱动器行为,通常涉及对传输数据的方式进行调整,以避免驱动器在等待操作完成时阻塞其他任务的执行。UVM提供了多个机制来支持非阻塞操作,包括使用TLM(Transaction Level Modeling)接口和异步通信方式。 UVM驱动器通常通过`uvm_driver`类实现,该类提供了一个`seq_item_port`用于接收事务(transaction)并驱动到DUT(Design Under Test)。为了实现非阻塞行为,可以使用`put`或`transport`等非阻塞TLM接口。例如,可以使用`nonblocking_put`接口来发送事务而不等待响应[^1]。 以下是一个简单的示例,展示如何在UVM驱动器中实现非阻塞传输: ```systemverilog class my_driver extends uvm_driver #(my_transaction); // 定义非阻塞的TLM端口 `uvm_component_utils(my_driver) // 非阻塞端口 uvm_nonblocking_put_port #(my_transaction) put_port; function new(string name, uvm_component parent); super.new(name, parent); put_port = new("put_port", this); endfunction virtual task run_phase(uvm_phase phase); my_transaction req; forever begin // 从序列器获取事务 seq_item_port.get_next_item(req); // 使用非阻塞方式发送事务 if (!put_port.try_put(req)) begin `uvm_error("DRIVER", "Failed to put transaction non-blockingly") end seq_item_port.item_done(); end endtask endclass ``` 在上述代码中,`try_put`方法用于尝试发送事务,如果当前无法发送(例如,目标端口忙),则立即返回失败状态,而不是等待。这种方式允许驱动器在无法立即完成传输时继续执行其他任务。 此外,还可以通过使用`transport`接口来实现非阻塞通信。`transport`接口允许驱动器发送请求并立即返回,而不必等待响应。这对于需要高吞吐量的应用场景非常有用。 总之,UVM提供了多种机制来实现非阻塞驱动器行为,开发者可以根据具体需求选择合适的接口和方法来优化驱动器的性能和效率。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值