使用线程在UDP聊天中使用一个套接字

2024-09-27 07:20:38 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在工作的UDP聊天,应该是监听和能够发送消息任何时候只用一个套接字。例如,我会有聊天程序完成,我会打开它第一次,然后第二次,我必须能够通过UDP从两个程序通信,简单地说,每个程序只有一个打开的套接字。在

我的两个线程是用来监听的,这是迪蒙线程,因为我想让它不停地听新消息,而我的另一个线程是发送消息,这和普通线程一样。在

首先,我的问题是,我的线程似乎在互相阻塞,因为如果我运行这个程序,我只能从我启动的第一个线程得到输出。在

第二个问题是,我不确定我的sending函数或整个类是否编写正确,或者是否有遗漏或不正确的地方。在

提前谢谢。顺便说一句,我是python新手,我正在使用python3,只是为了让大家明白。在

import socket
import threading
import logging
import time
from sys import byteorder


class Sending():
    def __init__(self, name, tHost, tPort):
        self.name = name
        self.host = tHost
        self.port = tPort

    def set_name(self, name):
        self.name = name

    def send(self, name, tHost, tPort, msgType, dgramSize):
        logging.debug('Starting send run')
        message = input('Enter message: ')
        data = bytearray()
        data.extend( (name.encode('utf-8'), message.encode('utf-8'), msgType.to_bytes(1, byteorder = 'little')) )
        #data.extend(message.encode(encoding='utf_8'))
        self.sock.sendto(bytearray(data), (tHost, tPort))

    def run(self):

        th2 = threading.Thread(name = 'send', target=self.send('username', 'localhost', 8001, 1, 1400))
        th2.start()

class Receiving():
    def __init__(self, host, port):
        self.host = host
        self.port = port

    def create_socket(self, host, port):
        logging.debug('Starting socket')
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)    
        sock.bind((host, port))
        #print ('socket ready')
        time.sleep(5)
        while True:
            data, addr = sock.recvfrom(1500)
            print('Prijata:' + data + addr)

    def run(self):

        th1 = threading.Thread(name = 'rec', target=self.create_socket('localhost', 8000))
        th1.setDaemon(True)
        th1.start()

if __name__ == '__main__':
    #print ('running')
    rec = Receiving('localhost', 8000)
    send = Sending('username', 'localhost', 8001)
    send.run()
    rec.run()    

Tags: runnameimportself程序sendhostmessage
2条回答

恭喜你对Python的介绍!看起来您使用的是python3,在以后的问题中,如果您清楚地知道您使用的是哪个版本,这将很有帮助,因为有些代码(包括这段代码!)中存在轻微但会破坏程序的不兼容性。在

我在你的程序中发现了一些错误:

  • 最主要的问题是,正如特雷弗·巴恩威尔所说,你打电话给threading.Thread并不太正确。target=参数需要是一个可调用的对象(即函数),但在本例中它应该只是对函数的引用。如果您像上面一样给函数self.create_socket(host, port)添加括号,它实际上会立即运行函数。正如Trevor所解释的,您的Sending.send()方法很早就被调用了,但是Receiving中还有一个类似的bug。因为接收.create_套接字()创建无限循环,它从不返回程序执行。虽然控制台输出在用户看来是正确的,但实际的程序执行从来没有让它在单独的线程中运行侦听器。

  • bytearray.extend()接受一个int的iterable,现在传递的是字节对象的元组。

  • Sending.send()中,您调用了self.sock,但是您从未给self.sock赋值,所以它失败了。

  • Sending.run()只运行Sending.send()一次。在为用户完成输入后,它会立即退出,因为程序已经完成。

如果您正在寻找一个适合有经验的程序员的基于项目的深入介绍Python(包括一个与这个问题非常相似的关于基本套接字的练习,另一个关于线程的练习),我强烈建议您查看Wesley Chun的“Core Python Applications Programming”。最新的版本(第3版)有很多python2代码,但是它很容易移植到python3,读者只需要做一些小的工作。在

我试图尽可能少地修改您的代码以使其正常工作,如下所示:

import socket
import threading
import logging
import time


class Sending():
    def __init__(self, name, tHost, tPort, target):
        self.name = name
        self.host = tHost
        self.port = tPort
        self.target_port = target
        self.sock = self.create_socket()

    def create_socket(self):
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.bind((self.host, self.port))
        return sock

    def set_name(self, name):
        self.name = name

    def send_loop(self):
        while True:
            logging.debug('Starting send run')
            message = input('Enter message: ')
            data = bytearray()
            data.extend(message.encode('utf-8'))
            self.sock.sendto(bytearray(data), (self.host, self.target_port))

    def run(self):
        th2 = threading.Thread(name='send', target=self.send_loop)
        th2.start()


class Receiving():
    def __init__(self, host, port):
        self.host = host
        self.port = port

    def create_socket(self):
        logging.debug('Starting socket')
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.bind((self.host, self.port))
        print ('socket ready')
        time.sleep(5)
        while True:
            data, addr = sock.recvfrom(1500)
            print('\nPrijata:' + data.decode('utf-8') + str(addr))

    def run(self):
        th1 = threading.Thread(name='rec', target=self.create_socket)
        print("Made it here")
        th1.daemon = True
        th1.start()
        return

if __name__ == '__main__':
    print('running')
    rec = Receiving('localhost', 8000)
    send = Sending('username', 'localhost', 8001, 8000)
    rec.run()
    send.run()

线程没有相互阻塞。send在创建线程之前被调用。在

th2 = threading.Thread(name = 'send', target=self.send('username', 'localhost', 8001, 1, 1400))

这条线路打电话到:

^{pr2}$

我想你是想这么做的:

th2 = threading.Thread(
    target=self.send
    args=('username', 'localhost', 8001, 1, 1400))

这样,一个线程将在下一行开始调用send。在

还有两件事:

  • 您将希望在函数中循环,因为一旦函数结束,线程就会终止。在
  • 我想你是说raw_input而不是{}

相关问题 更多 >

    热门问题