【问题标题】:A receiver that can receive both TCP images and UDP texts可以接收 TCP 图像和 UDP 文本的接收器
【发布时间】:2018-10-30 05:28:24
【问题描述】:

我是套接字编程的新手。我在同一主机上实现了 2 个单独的代码。其中一个应该使用 TCP 协议接收图像,第二个应该通过 UDP 协议接收文本消息。他们俩分别工作正常。以下是代码:

图像接收器 (TCP):

from __future__ import print_function
import socket
from struct import unpack
import Queue
from PIL import Image


HOST = '10.0.0.1'
PORT = 12345
BUFSIZE = 4096
q = Queue.Queue()

class Receiver:
    ''' Buffer binary data from socket conn '''
    def __init__(self, conn):
        self.conn = conn
        self.buff = bytearray()

    def get(self, size):
        ''' Get size bytes from the buffer, reading
            from conn when necessary 
        '''
        while len(self.buff) < size:
            data = self.conn.recv(BUFSIZE)
            if not data:
                break
            self.buff.extend(data)
        # Extract the desired bytes
        result = self.buff[:size]
        # and remove them from the buffer
        del self.buff[:size]
        return bytes(result)

    def save(self, fname):
        ''' Save the remaining bytes to file fname '''
        with open(fname, 'wb') as f:
            if self.buff:
                f.write(bytes(self.buff))
            while True:
                data = self.conn.recv(BUFSIZE)
                if not data:
                    break
                f.write(data)

def main():
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    try:
        sock.bind((HOST, PORT))
    except socket.error as err:
        print('Bind failed', err)
        return
    sock.listen(1)
    print('Socket now listening at', HOST, PORT)
    try:
        while True:
            conn, addr = sock.accept()
            print('Connected with', *addr)
            # Create a buffer for this connection
            receiver = Receiver(conn)
            # Get the length of the file name
            name_size = unpack('B', receiver.get(1))[0] 
            # Get the file name itself
            name = receiver.get(name_size).decode()
            q.put(name)
            print('name', name)
            # Save the file
            receiver.save(name)
            conn.close()
            print('saved\n')

    # Hit Break / Ctrl-C to exit
    except KeyboardInterrupt:
        print('\nClosing')

    sock.close()

if __name__ == '__main__':
    main()

文本接收器 (UDP):

import socket

UDP_IP = "10.0.0.1"
UDP_PORT = 5005
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))

while True:
    data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
    print "received message:", data

现在我的问题是:如何合并这两个代码?我不想为每个控制台打开 2 个单独的控制台,我想要一个代码而不是两个。有可能吗?


我尝试了评论中提供的解决方案,代码如下:

from __future__ import print_function
from select import select
import socket
from struct import unpack

host = '10.0.0.2'
port = 5005
size = 8000
backlog = 5

class Receiver:
    ''' Buffer binary data from socket conn '''
    def __init__(self, conn):
        self.conn = conn
        self.buff = bytearray()

    def get(self, size):
        ''' Get size bytes from the buffer, reading
            from conn when necessary 
        '''
        while len(self.buff) < size:
            data = self.conn.recv(BUFSIZE)
            if not data:
                break
            self.buff.extend(data)
        # Extract the desired bytes
        result = self.buff[:size]
        # and remove them from the buffer
        del self.buff[:size]
        return bytes(result)

    def save(self, fname):
        ''' Save the remaining bytes to file fname '''
        with open(fname, 'wb') as f:
            if self.buff:
                f.write(bytes(self.buff))
            while True:
                data = self.conn.recv(BUFSIZE)
                if not data:
                    break
                f.write(data)


def read_tcp(s):
    conn, addr = s.accept()
    print('Connected with', *addr)
    # Create a buffer for this connection
    receiver = Receiver(conn)
    # Get the length of the file name
    name_size = unpack('B', receiver.get(1))[0]
    name = receiver.get(name_size).decode()
    print('name', name)
    # Save the file
    receiver.save(name)
    conn.close()
    print('saved\n')

def read_udp(s):
    data,addr = s.recvfrom(8000)
    print("Recv UDP:'%s'" % data)

def run():

    # create tcp socket
    tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    tcp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    tcp.bind((host,port))
    tcp.listen(1)

    # create udp socket
    udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
    udp.bind((host,port))

    input = [tcp,udp]

    while True:
        inputready,outputready,exceptready = select(input,[],[])

        for s in inputready:
            if s == tcp:
                read_tcp(s)
            elif s == udp:
                read_udp(s)
            else:
                print("unknown socket:", s)

if __name__ == '__main__':
    run()

但我现在没有收到任何 UDP 或 TCP 数据包,而且它似乎对我不起作用。

【问题讨论】:

标签: python sockets


【解决方案1】:

简短回答是,但您需要为此实现多线程。例如,您的程序将生成两个线程,一个用于 TCP 套接字,另一个用于 UDP。

【讨论】:

  • 虽然这个问题可以使用多线程来解决,但多线程不是必需的(甚至不一定推荐)。您还可以使用单线程和 I/O 多路复用函数(如 select()poll())来完成相同的功能。
  • @JeremyFriesner 我不知道,谢谢!我需要阅读更多关于这些函数的信息。
猜你喜欢
  • 2013-01-20
  • 2021-12-14
  • 2017-10-24
  • 2011-09-16
  • 2016-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多