Приемник, который может получать как изображения TCP, так и тексты UDP - PullRequest
0 голосов
/ 29 октября 2018

Я новичок в программировании сокетов. Я реализовал 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 кода? Я не хочу открывать 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 сейчас, и, похоже, у меня не работает.

1 Ответ

0 голосов
/ 29 октября 2018

Короткий ответ: да, но для этого вам потребуется реализовать многопоточность. Например, ваша программа создаст два потока, один для сокетов TCP, а другой для UDP.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...