简体   繁体   English

服务器脚本未在 python sockets 中发送消息

[英]server script is not sending message in python sockets

i am trying to get message from a client using threads.I need to send the message to all the connected client threads my server code is我正在尝试使用线程从客户端获取消息。我需要将消息发送到我的服务器代码所在的所有连接的客户端线程

import socket
import threading

class seversocket:
    def __init__(self):
        self.header=64
        self.port=5055
        self.format='utf-8'
        self.hostname=socket.gethostname()
        self.host=socket.gethostbyname(self.hostname)
        self.close='close'
        self.messagelist=['world']
        self.addr=(self.host,self.port)
        self.soc=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        self.soc.bind(self.addr)
        print('server socket created and binded;')
        self.listener()
    def messageupdate(self,msgcount):
        result_list=[]
        if(len(self.messagelist)>msgcount):
            result_list=self.messagelist[msgcount:]
            return result_list,len(self.messagelist)
        else:
            return None,msgcount



    def clients(self,conn,addr):
        print(f'connected to {addr}')
        connected=True
        msgcount=0
        while connected:
            msglen=conn.recv(self.header).decode(self.format)
            if msglen:
                msglen=int(msglen)
                msg = conn.recv(msglen).decode(self.format)
                if msg == self.close:
                    connected=False
                print(f"[{addr}]{msg}")
            li,msgcount= self.messageupdate(msgcount)
            if li is not None:
                for i in li:
                    print(i)                    
                    message=i.encode(self.format)
                    print(message)
                    msglen=len(message)
                    print(msglen)
                    sendlen=str(msglen).encode(self.format)
                    sendlen += b' '*(self.header-len(sendlen))
                    conn.send(sendlen)
                    conn.send(message)



        conn.close()

    def listener(self):
        self.soc.listen()
        print(f'socket is listening to {self.host}')
        while True:
            conn,addr=self.soc.accept()
            thread=threading.Thread(target=self.clients,args=(conn,addr))
            thread.start()
    def listappened(self,mes):
        self.messagelist.append(mes)
        return None

seversocket()

my clientscript is我的客户脚本是

import socket
import threading

class clientsocket:
    def __init__(self):
        self.header=64
        self.port=5055
        self.format='utf-8'
        self.hostname=socket.gethostname()
        self.host=socket.gethostbyname(self.hostname)
        self.close='close'
        self.addr=(self.host,self.port)
        self.client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        self.client.connect(self.addr)
        self.check=threading.Thread(target=self.checkformessgae)
    def send(self,msg):
        message=msg.encode(self.format)
        msglen=len(message)
        sendlen=str(msglen).encode(self.format)
        sendlen += b' '*(self.header-len(sendlen))
        self.client.send(sendlen)
        self.client.send(message)
    def checkformessgae(self):
        msglen=self.client.recv(self.header).decode(self.format)
        if msglen:
            msglen=int(msglen)
            msg =self.client.recv(msglen).decode(self.format)
            if msg == self.close:
                connected=False
            print(f"[{addr}]{msg}")

k=clientsocket()
k.send('hello')

when i run the server the server is running,but when i run the clientscript server script throws the following error当我运行服务器时,服务器正在运行,但是当我运行 clientscript 服务器脚本时抛出以下错误

在此处输入图像描述

when i debug the code line by line the error i occuring in the serverscript when i try to send the message conn.send(sendlen) conn.send(message)当我逐行调试代码时,当我尝试发送消息 conn.send(sendlen) conn.send(message) 时出现在服务器脚本中的错误

So, a minimal example of your situation would be:因此,您的情况的一个最小示例是:

import socket, time
import threading

header = 64

soc = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
soc.bind(('', 5055))
soc.listen()
conn, addr = soc.accept()

def loop(conn):
    while True:
        msglen = conn.recv(header).decode('UTF-8')
        if msglen:
            msglen = int(msglen)
            msg = conn.recv(msglen).decode('UTF-8')
            print(msg)

            conn.send(b'10')
            conn.send(b'0123456789')

        time.sleep(0.025)

thread = threading.Thread(target=loop, args=(conn,))
thread.start()

Now, because threading has nothing to do with this, I can also reduce the code to the actual problem which is the socket part.现在,因为线程与此无关,我也可以将代码简化为实际问题,即套接字部分。
(This might come from experience, it might also just come from searching the issue online and you'll find plenty of resources covering "connection reset by peer") . (这可能来自经验,也可能只是来自在线搜索问题,您会发现大量资源涵盖“对等连接重置”)

So, if we reduce it to the core components of the issue, it looks like this:因此,如果我们将其简化为问题的核心组成部分,它看起来像这样:

import socket
# No threading needed to reproduce the problem

header = 64

soc = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
soc.bind(('', 5055))
soc.listen()
conn, addr = soc.accept()

while True: # Replaced thread with a simple while loop
    msglen = conn.recv(header).decode('UTF-8')
    if msglen:
        msglen = int(msglen)
        msg = conn.recv(msglen).decode('UTF-8')
        print(msg)

        conn.send(b'10')
        conn.send(b'0123456789')

Which gives me:这给了我:

PS C:\Users\anton> python .\server.py
hello
Traceback (most recent call last):
  File ".\server.py", line 12, in <module>
    msglen = conn.recv(header).decode('UTF-8')
ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host

Now, my error message is slightly different.现在,我的错误信息略有不同。 And that is because I'm on windows and you're on Linux.那是因为我在 windows 而你在 Linux。 But the jizt is the same, "Connection reset" by some party of the connection.但是 jizt 是相同的,连接的某些方“重置连接”。

Now, why is this?现在,这是为什么呢?
Quite simple, it's because the other end of the connection (client in this case, since the problem is on the server end of things) closed the connection.很简单,这是因为连接的另一端(在这种情况下是客户端,因为问题出在服务器端)关闭了连接。 And why is that?为什么是这样? Well it's because there's nothing keeping the client alive.那是因为没有什么可以让客户活着。 All it does is send hello , check if there's any incoming data and do print(f"[{addr}]{msg}") .它所做的只是发送hello ,检查是否有任何传入数据并执行print(f"[{addr}]{msg}") After that, the client quits.之后,客户退出。

So while that happens, you're trying to do (multiple times) :因此,当这种情况发生时,您正在尝试(多次)

conn.recv(msglen)

Which won't work because there's nothing on the other end.这是行不通的,因为另一端什么都没有。

So the solution to your problem is, don't quit the client.因此,解决您的问题的方法是,不要退出客户端。 And also, do error handling.而且,做错误处理。 There's a lot to cover in this topic as server and client side software has a lot of pitfalls.由于服务器端和客户端软件存在很多缺陷,因此本主题要涵盖的内容很多。 But in your case, doing:但在你的情况下,做:

try:
    ConnectionResetError
except ConnectionResetError:
    self.close()

Or you could switch to a more fault-friendly way of first checking if there's data via the select library.或者,您可以切换到一种对故障更友好的方式,首先通过select库检查是否有数据。

import socket, select

header = 64

soc = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
soc.bind(('', 5055))
soc.listen()
conn, addr = soc.accept()

while True:
    readable, writable, exceptional = select.select([conn], [conn], [])
    print(readable)
    if readable:
        msglen = conn.recv(header).decode('UTF-8')
        if msglen:
            msglen = int(msglen)
            msg = conn.recv(msglen).decode('UTF-8')
            print(msg)

            # Could technically check writable here, just to be sure
            print(writable)
            conn.send(b'10')
            conn.send(b'0123456789')

But even then, that might fail because of timing issue between checking and trying to read.但即便如此,由于检查和尝试阅读之间的时间问题,这可能会失败。 That's where epoll comes in, it can trigger on events and be a bit more flexible (maybe you can achieve the same with select.select but I gave up a long time ago so don't know myself) .这就是epoll的用武之地,它可以触发事件并且更加灵活(也许你可以用select.select实现相同的效果,但我很久以前就放弃了,所以不了解自己)

import socket, select

header = 64

soc = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
soc.bind(('', 5055))
soc.listen()
conn, addr = soc.accept()

poll_obj = select.epoll()
poll_obj.register(conn.fileno(), select.EPOLLIN | select.EPOLLHUP)

while True:
    for fileno, eventid in poll_obj.poll(0.5):
        if eventid == select.EPOLLIN:
            msglen = conn.recv(header).decode('UTF-8')
            if msglen:
                msglen = int(msglen)
                msg = conn.recv(msglen).decode('UTF-8')
                print(msg)

                conn.send(b'10')
                conn.send(b'0123456789')
        else:
            print('Client disconnected (prob eventid 25)')
            break

This will firstly verify that there's data on the pipe, then it will determinate if the data is actual data or if it's a underlying socket event ( RST/ACK for instance was sent).这将首先验证 pipe 上有数据,然后确定数据是实际数据还是底层套接字事件(例如发送了RST/ACK )。 If all is OK, you (should) can probably receive data without errors.如果一切正常,您(应该)可能可以无错误地接收数据。 As long as you handle the disconnects.只要您处理断开连接。

Bake this into your thread logic again, and you should be good to go.再次将其放入您的线程逻辑中,您应该对 go 很好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM