- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我有一个简单的问题,代码如下。希望我没有在代码中犯错。
我是一名网络工程师,我需要测试我们的业务应用程序在网络中断期间保持事件状态的某些 Linux 行为(稍后我将插入一些 iptables 东西来插接连接 - 首先我想确保我正确设置了客户端和服务器)。
作为我正在进行的网络故障测试的一部分,我编写了一个非阻塞的 Python TCP 客户端和服务器,它们应该在循环中盲目地相互发送消息。为了了解发生了什么,我使用了循环计数器。
服务器的循环应该相对简单。我遍历每个 select
说准备就绪的 fd。我什至从未在服务器代码中的任何地方导入 sleep
。从这个角度来看,我不希望服务器代码在客户端套接字
上循环时暂停,但由于某种原因,服务器代码间歇性暂停
(更多详细信息,下文)。
我最初并没有让客户的循环休眠。在客户端没有休眠的情况下,服务器和客户端似乎和我想要的一样高效。但是,当我在客户端对服务器执行 fd.send()
之后放置 time.sleep(1)
语句时,TCP服务器代码在客户端休眠时
间歇
暂停。
我的问题:
fd.send( )
循环?如果是这样,我做错了什么?
我在两台 RHEL6 Linux 机器上运行它。要重现问题...
SERVER_HOSTNAME
和 SERVER_DOMAIN
更改为您在其上运行的服务器的主机名和域客户端连接后,您会看到在服务器终端中快速滚动显示的消息,如 EXHIBIT 1 所示。
几秒钟后
当客户端点击time.sleep()
时,滚动暂停
间歇性
。我不希望看到这些停顿,但也许我误解了什么。
图表 1
---
LOOP_COUNT 0
---
LOOP_COUNT 1
---
LOOP_COUNT 2
---
LOOP_COUNT 3
CLIENTMSG: 'client->server 0'
---
LOOP_COUNT 4
---
LOOP_COUNT 5
---
LOOP_COUNT 6
---
LOOP_COUNT 7
---
LOOP_COUNT 8
---
LOOP_COUNT 9
---
LOOP_COUNT 10
---
LOOP_COUNT 11
---
If I wrote this test code correctly and the server shouldn't pause, why is the TCP server intermittently pausing while it polls the client's connection for data?
回答我自己的问题。我的阻塞问题是由使用非零超时调用 select() 引起的。
当我将 select() 更改为使用零秒超时时,我得到了预期的结果。
tcp_server.py
#!/usr/bin/python -u
from socket import AF_INET, SOCK_STREAM, SO_REUSEADDR, SOL_SOCKET
from socket import MSG_DONTWAIT
#from socket import MSG_OOB <--- for send()
from socket import socket
import socket as socket_module
import select
import errno
import fcntl
import time
import sys
import os
def get_errno_info(e, op='', debugmsg=False):
"""Return verbose information from errno errors, such as errors returned by python socket()"""
VALID_OP = set(['accept', 'connect', 'send', 'recv', 'read', 'write'])
assert op.lower() in VALID_OP, "op must be: {0}".format(
','.join(sorted(VALID_OP)))
## ref: man 3 errno (in linux)... other systems may be man 2 intro
## also see https://docs.python.org/2/library/errno.html
try:
retval_int = int(e.args[0]) # Example: 32
retval_str = os.strerror(e.args[0]) # Example: 'Broken pipe'
retval_code = errno.errorcode.get(retval_int, 'MODULEFAIL') # Ex: EPIPE
except:
## I don't expect to get here unless something broke in python errno...
retval_int = -1
retval_str = '__somethingswrong__'
retval_code = 'BADFAIL'
if debugmsg:
print "DEBUG: Can't {0}() on socket (errno:{1}, code:{2} / {3})".format(
op, retval_int, retval_code, retval_str)
return retval_int, retval_str, retval_code
host = ''
port = 6667 # IRC service
DEBUG = True
serv_sock = socket(AF_INET, SOCK_STREAM)
serv_sock.setsockopt(SOL_SOCKET, SOCK_STREAM, 1)
serv_sock.bind((host, port))
serv_sock.listen(5)
#fcntl.fcntl(serv_sock, fcntl.F_SETFL, os.O_NONBLOCK) # Make the socket non-blocking
serv_sock.setblocking(False)
sock_list = [serv_sock]
from_client_str = '__DEFAULT__'
to_client_idx = 0
loop_count = 0
need_send_select = False
while True:
if need_send_select:
# Only do this after send() EAGAIN or EWOULDBLOCK...
send_sock_list = sock_list
else:
send_sock_list = []
#print "---"
#print "LOOP_COUNT", loop_count
recv_ready_list, send_ready_list, exception_ready = select.select(
sock_list, send_sock_list, [], 0.0) # Last float is the select() timeout...
## Read all sockets which are output-ready... might be client or server...
for sock_fd in recv_ready_list:
# accept() if we're reading on the server socket...
if sock_fd is serv_sock:
try:
clientsock, clientaddr = sock_fd.accept()
except socket_module.error, e:
errstr, errint, errcode = get_errno_info(e, op='accept',
debugmsg=DEBUG)
assert sock_fd.gettimeout()==0.0, "client socket should be in non-blocking mode"
sock_list.append(clientsock)
# read input from the client socket...
else:
try:
from_client_str = sock_fd.recv(1024, MSG_DONTWAIT)
if from_client_str=='':
# Client closed the socket...
print "CLIENT CLOSED SOCKET"
sock_list.remove(sock_fd)
except socket_module.error, e:
errstr, errint, errcode = get_errno_info(e, op='recv',
debugmsg=DEBUG)
if errcode=='EAGAIN' or errcode=='EWOULDBLOCK':
# socket unavailable to read()
continue
elif errcode=='ECONNRESET' or errcode=='EPIPE':
# Client closed the socket...
sock_list.remove(sock_fd)
else:
print "UNHANDLED SOCKET ERROR", errcode, errint, errstr
sys.exit(1)
print "from_client_str: '{0}'".format(from_client_str)
## Adding dynamic_list, per input from EJP, below...
if need_send_select is False:
dynamic_list = sock_list
else:
dynamic_list = send_ready_list
## NOTE: socket code shouldn't walk this list unless a write is pending...
## broadast the same message to all clients...
for sock_fd in dynamic_list:
## Ignore server's listening socket...
if sock_fd is serv_sock:
## Only send() to accept()ed sockets...
continue
try:
to_client_str = "server->client: {0}\n".format(to_client_idx)
send_retval = sock_fd.send(to_client_str, MSG_DONTWAIT)
## send() returns the number of bytes written, on success
## disabling assert check on sent bytes while using MSG_DONTWAIT
#assert send_retval==len(to_client_str)
to_client_idx += 1
need_send_select = False
except socket_module.error, e:
errstr, errint, errcode = get_errno_info(e, op='send',
debugmsg=DEBUG)
if errcode=='EAGAIN' or errcode=='EWOULDBLOCK':
need_send_select = True
continue
elif errcode=='ECONNRESET' or errcode=='EPIPE':
# Client closed the socket...
sock_list.remove(sock_fd)
else:
print "FATAL UNHANDLED SOCKET ERROR", errcode, errint, errstr
sys.exit(1)
loop_count += 1
tcp_client.py
#!/usr/bin/python -u
from socket import AF_INET, SOCK_STREAM
from socket import MSG_DONTWAIT # non-blocking send/recv; see man 2 recv
from socket import gethostname, socket
import socket as socket_module
import select
import fcntl
import errno
import time
import sys
import os
## NOTE: Using this script to simulate a scheduler
SERVER_HOSTNAME = 'myServerHostname'
SERVER_DOMAIN = 'mydomain.local'
PORT = 6667
DEBUG = True
def get_errno_info(e, op='', debugmsg=False):
"""Return verbose information from errno errors, such as errors returned by python socket()"""
VALID_OP = set(['accept', 'connect', 'send', 'recv', 'read', 'write'])
assert op.lower() in VALID_OP, "op must be: {0}".format(
','.join(sorted(VALID_OP)))
## ref: man 3 errno (in linux)... other systems may be man 2 intro
## also see https://docs.python.org/2/library/errno.html
try:
retval_int = int(e.args[0]) # Example: 32
retval_str = os.strerror(e.args[0]) # Example: 'Broken pipe'
retval_code = errno.errorcode.get(retval_int, 'MODULEFAIL') # Ex: EPIPE
except:
## I don't expect to get here unless something broke in python errno...
retval_int = -1
retval_str = '__somethingswrong__'
retval_code = 'BADFAIL'
if debugmsg:
print "DEBUG: Can't {0}() on socket (errno:{1}, code:{2} / {3})".format(
op, retval_int, retval_code, retval_str)
return retval_int, retval_str, retval_code
connect_finished = False
while not connect_finished:
try:
c2s = socket(AF_INET, SOCK_STREAM) # Client to server socket...
# Set socket non-blocking
#fcntl.fcntl(c2s, fcntl.F_SETFL, os.O_NONBLOCK)
c2s.connect(('.'.join((SERVER_HOSTNAME, SERVER_DOMAIN,)), PORT))
c2s.setblocking(False)
assert c2s.gettimeout()==0.0, "c2s socket should be in non-blocking mode"
connect_finished = True
except socket_module.error, e:
errstr, errint, errcode = get_errno_info(e, op='connect',
debugmsg=DEBUG)
if errcode=='EINPROGRESS':
pass
to_srv_idx = 0
need_send_select = False
while True:
socket_list = [c2s]
# Get the list sockets which can: take input, output, etc...
if need_send_select:
# Only do this after send() EAGAIN or EWOULDBLOCK...
send_sock_list = socket_list
else:
send_sock_list = []
recv_ready_list, send_ready_list, exception_ready = select.select(
socket_list, send_sock_list, [])
for sock_fd in recv_ready_list:
assert sock_fd is c2s, "Strange socket failure here"
#incoming message from remote server
try:
from_srv_str = sock_fd.recv(1024, MSG_DONTWAIT)
except socket_module.error, e:
## https://stackoverflow.com/a/16745561/667301
errstr, errint, errcode = get_errno_info(e, op='recv',
debugmsg=DEBUG)
if errcode=='EAGAIN' or errcode=='EWOULDBLOCK':
# Busy, try again later...
print "recv() BLOCKED"
continue
elif errcode=='ECONNRESET' or errcode=='EPIPE':
# Server ended normally...
sys.exit(0)
## NOTE: if we get this far, we successfully received from_srv_str.
## Anything caught above, is some kind of fail...
print "from_srv_str: {0}".format(from_srv_str)
## Adding dynamic_list, per input from EJP, below...
if need_send_select is False:
dynamic_list = socket_list
else:
dynamic_list = send_ready_list
for sock_fd in dynamic_list:
# outgoing message to remote server
if sock_fd is c2s:
try:
to_srv_str = 'client->server {0}'.format(to_srv_idx)
sock_fd.send(to_srv_str, MSG_DONTWAIT)
##
time.sleep(1) ## Client blocks the server here... Why????
##
to_srv_idx += 1
need_send_select = False
except socket_module.error, e:
errstr, errint, errcode = get_errno_info(e, op='send',
debugmsg=DEBUG)
if errcode=='EAGAIN' or errcode=='EWOULDBLOCK':
## Try to send() later...
print "send() BLOCKED"
need_send_select = True
continue
elif errcode=='ECONNRESET' or errcode=='EPIPE':
# Server ended normally...
sys.exit(0)
tcp_server.py
#!/usr/bin/python -u
from socket import AF_INET, SOCK_STREAM, SO_REUSEADDR, SOL_SOCKET
#from socket import MSG_OOB <--- for send()
from socket import socket
import socket as socket_module
import select
import fcntl
import os
host = ''
port = 9997
serv_sock = socket(AF_INET, SOCK_STREAM)
serv_sock.setsockopt(SOL_SOCKET, SOCK_STREAM, 1)
serv_sock.bind((host, port))
serv_sock.listen(5)
fcntl.fcntl(serv_sock, fcntl.F_SETFL, os.O_NONBLOCK) # Make the socket non-blocking
sock_list = [serv_sock]
from_client_str = '__DEFAULT__'
to_client_idx = 0
loop_count = 0
while True:
recv_ready_list, send_ready_list, exception_ready = select.select(sock_list, sock_list,
[], 5)
print "---"
print "LOOP_COUNT", loop_count
## Read all sockets which are input-ready... might be client or server...
for sock_fd in recv_ready_list:
# accept() if we're reading on the server socket...
if sock_fd is serv_sock:
clientsock, clientaddr = sock_fd.accept()
sock_list.append(clientsock)
# read input from the client socket...
else:
try:
from_client_str = sock_fd.recv(4096)
if from_client_str=='':
# Client closed the socket...
print "CLIENT CLOSED SOCKET"
sock_list.remove(sock_fd)
except socket_module.error, e:
print "WARNING RECV FAIL"
print "from_client_str: '{0}'".format(from_client_str)
for sock_fd in send_ready_list:
if sock_fd is not serv_sock:
try:
to_client_str = "server->client: {0}\n".format(to_client_idx)
sock_fd.send(to_client_str)
to_client_idx += 1
except socket_module.error, e:
print "TO CLIENT SEND ERROR", e
loop_count += 1
tcp_client.py
#!/usr/bin/python -u
from socket import AF_INET, SOCK_STREAM
from socket import gethostname, socket
import socket as socket_module
import select
import fcntl
import errno
import time
import sys
import os
## NOTE: Using this script to simulate a scheduler
SERVER_HOSTNAME = 'myHostname'
SERVER_DOMAIN = 'mydomain.local'
PORT = 9997
def handle_socket_error_continue(e):
## non-blocking socket info from:
## https://stackoverflow.com/a/16745561/667301
print "HANDLE_SOCKET_ERROR_CONTINUE"
err = e.args[0]
if (err==errno.EAGAIN) or (err==errno.EWOULDBLOCK):
print 'CLIENT DEBUG: No data input from server'
return True
else:
print 'FROM SERVER RECV ERROR: {0}'.format(e)
sys.exit(1)
c2s = socket(AF_INET, SOCK_STREAM) # Client to server socket...
c2s.connect(('.'.join((SERVER_HOSTNAME, SERVER_DOMAIN,)), PORT))
# Set socket non-blocking...
fcntl.fcntl(c2s, fcntl.F_SETFL, os.O_NONBLOCK)
to_srv_idx = 0
while True:
socket_list = [c2s]
# Get the list sockets which can: take input, output, etc...
recv_ready_list, send_ready_list, exception_ready = select.select(
socket_list, socket_list, [])
for sock_fd in recv_ready_list:
assert sock_fd is c2s, "Strange socket failure here"
#incoming message from remote server
try:
from_srv_str = sock_fd.recv(4096)
except socket_module.error, e:
## https://stackoverflow.com/a/16745561/667301
err_continue = handle_socket_error_continue(e)
if err_continue is True:
continue
else:
if len(from_srv_str)==0:
print "SERVER CLOSED NORMALLY"
sys.exit(0)
## NOTE: if we get this far, we successfully received from_srv_str.
## Anything caught above, is some kind of fail...
print "from_srv_str: {0}".format(from_srv_str)
for sock_fd in send_ready_list:
#incoming message from remote server
if sock_fd is c2s:
#to_srv_str = raw_input('Send to server: ')
try:
to_srv_str = 'client->server {0}'.format(to_srv_idx)
sock_fd.send(to_srv_str)
##
time.sleep(1) ## Client blocks the server here... Why????
##
to_srv_idx += 1
except socket_module.error, e:
print "TO SERVER SEND ERROR", e
最佳答案
TCP 套接字几乎总是准备好写入,除非它们的套接字发送缓冲区已满。
因此,始终选择套接字的可写性是不正确的。您应该只在遇到由于 EAGAIN/EWOULDBLOCK 导致的发送失败后才这样做。否则您的服务器将无意识地旋转处理可写套接字,通常是所有套接字。
关于python - 如果 TCP 客户端能够暂停服务器,当 TCP 服务器读取非阻塞套接字时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51549719/
我正在使用 Java 编写一个时钟程序,该程序能够“滴答作响”,但它存在问题。我认为它与 getter 和 setter 或 toString() 方法有关。 计数器类 package clock;
const Index = () => { // Ref Links const frefLinks = { 1: useRef(1), 2: useRef(2), 3: useRef(3
所以我读了here不能 pickle 装饰函数。确实: import multiprocessing as mp def deco(f): def wrapper(*args, **kwarg
我在go1.11.2 linux/amd64 版本。当包godog使用 go get github.com/DATA-DOG/godog/ 安装,godog 可执行文件在 $GOPATH/bin/中创
如何正确压缩字符串,以便 PHP 能够解压缩? 我试过这个: public static byte[] compress(String string) throws IOException {
我们这里的问题是表明 在测试中使用 Kleene 代数。 在 b 的值由 p 保留的情况下,我们有交换条件 bp = pb;两个程序之间的等价性简化为等式 在 b 的值不被 p 保留的情况下,我们有交
我有一个与我的网络相关的非常奇怪的问题,我在具有多个接口(interface)的 VirtualBox 上安装了 RDO Grizzly OpenStack。 虚拟盒子: eth0 - managem
我正在尝试使用 Passport.js授权谷歌OAuth2在 Node.js .我整个星期都在尝试让它工作,但不知道为什么它不工作,所以现在我求助于 stack 寻求一些潜在的帮助。我已经尝试了所有在
我是一名优秀的程序员,十分优秀!