我有一个套接字编程情况,客户端关闭套接字的写入端,让服务器知道输入已完成(通过接收EOF),但保持读取结束打开以读回结果(一行文本).服务器知道客户端已成功读取结果并关闭套接字(或至少关闭读取端)将是有用的.有没有一种检查/等待这种状态的好方法?
不可以.所有你能知道的是你的发送是否成功,并且由于TCP缓冲,其中一些甚至在对等读取关闭后也会成功.
这是糟糕的设计.如果服务器需要知道客户端收到数据,则客户端需要确认它,这意味着它无法关闭其写入端.客户应该:
服务器应检测带内终止消息,并且:
或者,如果目标只是确保客户端和服务器同时结束,则每个端都应关闭其套接字以进行输出,然后读取输入直到流结束,然后关闭套接字.这样,最终关闭将在两端或多或少同时发生.
getsockopt用TCP_INFO似乎是最明显的选择,但它不是跨平台的.
这是Linux的一个例子:
import socket
import time
import struct
import pprint
def tcp_info(s):
rv = dict(zip("""
state ca_state retransmits probes backoff options snd_rcv_wscale
rto ato snd_mss rcv_mss unacked sacked lost retrans fackets
last_data_sent last_ack_sent last_data_recv last_ack_recv
pmtu rcv_ssthresh rtt rttvar snd_ssthresh snd_cwnd advmss reordering
rcv_rtt rcv_space
total_retrans
pacing_rate max_pacing_rate bytes_acked bytes_received segs_out segs_in
notsent_bytes min_rtt data_segs_in data_segs_out""".split(),
struct.unpack("BBBBBBBIIIIIIIIIIIIIIIIIIIIIIIILLLLIIIIII",
s.getsockopt(socket.IPPROTO_TCP, socket.TCP_INFO, 160))))
wscale = rv.pop("snd_rcv_wscale")
# bit field layout is up to compiler
# FIXME test the order of nibbles
rv["snd_wscale"] = wscale >> 4
rv["rcv_wscale"] = wscale & 0xf
return rv
for i in range(100):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("localhost", 7878))
s.recv(10)
pprint.pprint(tcp_info(s))
Run Code Online (Sandbox Code Playgroud)
我怀疑是否存在真正的跨平台替代方案.
从根本上说,有很多州:
shutdown(WR)(几乎与关闭相同)显然,你的操作系统可以区分这些状态中的很多,但不是全部.我想不出一个API就是这个冗长的......
某些系统允许您查询剩余的发送缓冲区空间.也许如果你这样做,并且套接字已经关闭,你会得到一个整洁的错误?
好消息是因为套接字被关闭,并不意味着你无法查询它.TCP_INFO关闭后,我可以获得所有state=7关闭.在某些情况下报告state=8(等待等待).
http://lxr.free-electrons.com/source/net/ipv4/tcp.c#L1961拥有Linux TCP状态机的所有细节.
| 归档时间: |
|
| 查看次数: |
718 次 |
| 最近记录: |