Python 尝试对非套接字的对象执行操作(尝试了大量修复)
在你说这是一个副本之前,我已经看了很多关于这个的文章,仍然无法修复它。 我正在制作一个非常基本的聊天客户端和服务器python程序 但是,通过我的客户端连接后,服务器控制台上会显示“已连接”,但聊天室控制台上会立即断开连接,错误为“OSError:[WinError 10038]尝试对非连接的对象执行操作 插座 聊天Python 尝试对非套接字的对象执行操作(尝试了大量修复),python,windows,sockets,Python,Windows,Sockets,在你说这是一个副本之前,我已经看了很多关于这个的文章,仍然无法修复它。 我正在制作一个非常基本的聊天客户端和服务器python程序 但是,通过我的客户端连接后,服务器控制台上会显示“已连接”,但聊天室控制台上会立即断开连接,错误为“OSError:[WinError 10038]尝试对非连接的对象执行操作 插座 聊天 从中选择: Windows上的文件对象是不可接受的,但套接字是可接受的。在…上 在Windows中,基础select()函数由WinSock提供 并且不处理非源文件的文件描述符 来
从
中选择:
Windows上的文件对象是不可接受的,但套接字是可接受的。在…上
在Windows中,基础select()函数由WinSock提供
并且不处理非源文件的文件描述符
来自WinSock
这排除了使用sys.stdin
的可能性
备选方案:
- 使用(无需修改代码)
- 创建一个等待sys.stdin的线程(比如)
- 走完整的Windows路线并使用
- 使用一些将这些细节抽象出来的库,我喜欢但还没有在python中使用它
另一件事:不要在无限循环中使用超时为零的select
。这种忙碌的等待真的没有效率。相反,忽略超时以使选择块,直到描述符就绪。对于Python 3,ctypes.pythonapi.\u PyOS\u siginEvent()
返回为SIGINT
设置的Windows事件的句柄。将其附加到句柄数组中,以允许调用WaitForMultipleObjects
可被Ctrl+C中断。Python 3的\u winapi.WaitForMultipleObjects
会为您执行此操作,但前提是不要要求它等待所有对象,因为要求等待Ctrl+C是没有意义的。
def chat_client():
if(len(sys.argv) not in (3, 4)):
print("Usage: python chat_client.py <hostname> <port> <optional-username>\n")
sys.exit()
host = sys.argv[1]
port = int(sys.argv[2])
username = ""
if len(sys.argv) == 4:
username = sys.argv[3]
else:
username = "Guest"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(2)
# Connect to remote host
try:
s.connect((host, port))
except:
print("Unable to connect")
sys.exit()
print("Connected to remote host. You can start sending messages")
print("*** Press Control-C to log off ***\n")
sys.stdout.write("[" + username + "] ")
sys.stdout.flush()
while True:
socket_list = [sys.stdin, s]
try:
# Get the list sockets which are readable
ready_to_read, ready_to_write, in_error = select.select(socket_list, [], [])
except KeyboardInterrupt:
system("clear")
sys.stdout.write("\nYou have logged off\n")
sys.stdout.flush()
sys.exit()
HOST = ""
SOCKET_LIST = []
RECV_BUFFER = 4096
PORT = 9009
CONVERSATION = ""
def chat_server():
global CONVERSATION
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen(10)
# Add server socket object to the list of readable connections
SOCKET_LIST.append(server_socket)
print("Chat server started on port " + str(PORT))
while True:
try:
# Get the list sockets which are ready to be read through select
# 4th arg, time_out = 0 : poll and never block
ready_to_read, ready_to_write, in_error = select.select(SOCKET_LIST, [], [], 0)
for sock in ready_to_read:
# A new connection request recieved
if sock == server_socket:
sockfd, addr = server_socket.accept()
SOCKET_LIST.append(sockfd)
print("Client (%s, %s) connected" % addr)
broadcast(server_socket, sockfd, "[%s, %s] entered our chatting room\n" % addr)
# A message from a client, not a new connection
else:
# Process data recieved from client
try:
# Recieving data from socket
data = sock.recv(RECV_BUFFER)
if data:
# there is something in the socket
# broadcast(server_socket, sock, "\r" + '[' + str(sock.getpeername()) + '] ' + data) # old
broadcast(server_socket, sock, "\r" + data)
else:
# Remove the socket that's broken
if sock in SOCKET_LIST:
SOCKET_LIST.remove(sock)
# at this stage, no data probably means the connection has been broken
broadcast(server_socket, sock, "Client (%s, %s) is offline\n" % addr)
except:
broadcast(server_socket, sock, "Client (%s, %s) is offline\n" % addr)
continue
except KeyboardInterrupt:
server_socket.close()
sys.exit()
server_socket.close()
# broadcast chat messages to all connected clients
def broadcast(server_socket, sock, message):
for socket in SOCKET_LIST:
# send the message only to peer
if socket != server_socket and socket != sock:
try:
socket.send(message)
except:
# Broken socket connection
socket.close()
# Broken socket, remove it
if socket in SOCKET_LIST:
SOCKET_LIST.remove(socket)
if __name__ == "__main__":
sys.exit(chat_server())