Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/powerbi/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
python中的发送和接收包_Python_Sockets_Tcp - Fatal编程技术网

python中的发送和接收包

python中的发送和接收包,python,sockets,tcp,Python,Sockets,Tcp,这是TCP套接字服务器上的控制台聊天应用程序。客户端将向服务器发送请求/消息,服务器将向目标用户分发消息或提供请求的信息。我当前遇到了服务器端recv包的问题。我收到了包裹,可以打印出来。然而,由于某些原因,系统仍然给我一个语法错误 谢谢 这是我的客户: import socket import select import errno import sys, struct import pickle HEADER_LENGTH = 1024 IP = "127.0.0.1"

这是TCP套接字服务器上的控制台聊天应用程序。客户端将向服务器发送请求/消息,服务器将向目标用户分发消息或提供请求的信息。我当前遇到了服务器端recv包的问题。我收到了包裹,可以打印出来。然而,由于某些原因,系统仍然给我一个语法错误

谢谢

这是我的客户:

import socket
import select
import errno
import sys, struct
import pickle

HEADER_LENGTH = 1024
IP = "127.0.0.1"
PORT = 9669

def send_login_request(username):
    package = [1]
    length = len(username)
    if length > 1019:
        print ("Error: Username too long")
        sys.exit()
    package += struct.pack("I", length)
    package += username
    
    return package

def send_message(recv_id, message):
    package = [2]
    length = len(message)
    if length > 1015:
        print('message too long')
        sys.exit()
    package += recv_id
    package += struct.pack('I', length)
    package += message
    return package

def send_con_request(conv_id):
    package = [3]
    length = len(id)
    if length > 1015:
        print('id too long')
        sys.exit()
    package += struct.pack("I", length)
    package += conv_id
    return package
# Create a socket

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# Connect to a given ip and port
client_socket.connect((IP, PORT))

client_socket.setblocking(False)
my_username = input("Username: ")
request = send_login_request(my_username)
user_request = str(request)
client_socket.send(user_request.encode())
username_conf = client_socket.recv(HEADER_LENGTH).decode()
if username_conf == "Welcome to the server":
    con_id = input("Please enter conversation's id, if don't have one, please enter no ")
    if con_id == 'no':
        con_request = send_con_request(con_id)
        con_request = str(con_request)
        client_socket.send(con_request.encode())

    else: 
        con_request = send_con_request(con_id)
        con_request = str(con_request)
        client_socket.send(con_request.encode())

    conversation = client_socket.recv(HEADER_LENGTH).decode()

    recv_id = input("Please enter receiver's id")

    while True:
            # Wait for user to input a message

            message = input(f'{my_username} > ').encode()
            # If message is not empty - send it
            if message:

                send_message = send_message(recv_id,message)
                client_socket.send(bytes(send_message))

            try:

                while True:
                    message_receiver = client_socket.recv(HEADER_LENGTH).decode()
                    x = message_receiver.split('|')
                    print(x)
                    username = x[0]
                    message = x[1]
                    # Print message
                    print(f'{username} > {message}')

            except IOError as e:

                if e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK:
                    print('Reading error: {}'.format(str(e)))
                    sys.exit()

                # We just did not receive anything
                continue

            except Exception as e:
                # Any other exception - something happened, exit
                print('Reading error: {}'.format(str(e)))
                sys.exit()
这是我的服务器:

import socket
import select
import struct
import sys
import pickle

HEADER_LENGTH = 1024
conversation ={}
users = [
    {
        'username': 'user1',
        'user_id': 1
    },
    {
        'username': 'user2',
        'user_id': 2
    },
    {
        'username': 'user3',
        'user_id': 3
    },
    {
        'username': 'user4',
        'user_id': 4
    },
    {
        'username': 'user5',
        'user_id': 5
    }
]

def login(username):
    for user in users:
        if user['username'] == username:
            return user
        else: 
            return False
        

IP = "127.0.0.1"
PORT = 9669

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

server_socket.bind((IP, PORT))

server_socket.listen()

# List of sockets for select.select()
sockets_list = [server_socket]

# List of connected clients - socket as a key, user header and name as data
clients_socket = {}

sessions = {
    (1,2) : '1.txt',

    (3,4) : '2.txt'

}




def getRecvSocket(user_id):
    try:
        return sessions[user_id]
    except:
        return None

def sendErrorMes(socketid, mes):
    package = [9]
    length = len(mes)
    if length > 1019:
        length = 1019
    package += struct.pack("I", length)
    package += mes
    

print(f'Listening for connections on {IP}:{PORT}...')

# Handles message receiving

def receive_message(client_socket):

    try:
        receive_message = client_socket.recv(HEADER_LENGTH)
        return receive_message
    except:
        return False

while True:

    read_sockets, _, exception_sockets = select.select(sockets_list, [], sockets_list)

    # Iterate over notified sockets
    for notified_socket in read_sockets:

        # If notified socket is a server socket - new connection, accept it
        if notified_socket == server_socket:

            client_socket, client_address = server_socket.accept()
            
            sockets_list.append(client_socket)
            
        else:
        # Receive message
            
            package = receive_message(notified_socket)
            print(package)
            package_recv = eval(package.decode())
            print(package_recv)
            print(type(package_recv))
            package_type = package_recv[0]
            if package_type == 1:
                size = struct.unpack("I", package[1:5])
                if size[0] > 1019:
                    continue
                username = package[5:5+size[0]]
                username = username.decode()
                # username = package_recv[1]
                user = login(username)
                if user == False: 
                    notified_socket.send("no user found".encode())
                else: 
                    sessions[user["user_id"]] = notified_socket
                    notified_socket.send(("Welcome to the server").encode())
            elif package_type == 2:
                recv_id = struct.unpack("I", package[1:5])
                size = struct.unpack("I", package[5:9])
                if size[0] > 1015:
                    continue
                # recv_id = package_recv[1]
                if getRecvSocket(recv_id) == None:
                    sendErrorMes(notified_socket, "User is offline")
                else:
                    message = package[9:9+size[0]]
                    # message = package_recv[2]
                    for socket in sessions.values(): 
                        if socket == notified_socket: 
                            user = sessions[notified_socket]

                            # print(f'Received message from {user}, {message}')
            
                    # fIterate over connected clients and broadcast message
                    for client_socket in clients_socket:
                        # if clients[client_socket] == receive_user and client_socket != notified_socket:
                        # But don't sent it to sender
                        if client_socket != notified_socket and clients_socket[client_socket] == recv_id:

                            # Send user and message (both with their headers)
                            # We are reusing here message header sent by sender, and saved username header send by user when he connected
                            a = sessions[notified_socket]
                            b = recv_id 
                            with open(f"{conversation[a,b]}.txt", "w"):
                                f.write(user + message)


                            client_socket.send((user + "|" + message).encode())
                            
                    if message is False:
                        # print('Closed connection from: {}'.format(user))

                        # Remove from list for socket.socket()
                        sockets_list.remove(notified_socket)

                        # Remove from our list of users
                        del clients_socket[notified_socket]

                        continue
            
            elif package_type == 3: 
                size = struct.unpack("I", package[1:5])
                if size[0] > 1019:
                    continue
                convo_id = package[5:5+size[0]]
                convo_id = convo_id.decode()
                # convo_id = package_recv[2]
                if convo_id in conversation:
                    with open(conversation[convo_id], 'rb') as file_to_send:
                        for data in file_to_send:
                            notified_socket.sendall(data)
                    print('send successful')

                else: 
                    f = open(f"{len(conversation)+1}.txt", "w+")
这是服务器端的错误,我需要查找并解决该错误:

Listening for connections on 127.0.0.1:9669...
b"[1, 5, 0, 0, 0, 'u', 's', 'e', 'r', '1']"
[1, 5, 0, 0, 0, 'u', 's', 'e', 'r', '1']
<class 'list'>
b''
Traceback (most recent call last):
  File "c:/Users/Duong Dang/Desktop/bai 2.3/server.py", line 134, in <module>
    package_recv = eval(package.decode())
  File "<string>", line 0

    ^
SyntaxError: unexpected EOF while parsing
正在127.0.0.1:9669上侦听连接。。。
b“[1,5,0,0,0,'u','s','e','r','1']”
[1,5,0,0,0,'u','s','e','r','1']
b“
回溯(最近一次呼叫最后一次):
文件“c:/Users/Duong-Dang/Desktop/bai 2.3/server.py”,第134行,在
package_recv=eval(package.decode())
文件“”,第0行
^
SyntaxError:分析时出现意外的EOF

发送代码没有多大意义。您正在创建一个python列表,这是实现协议最奇怪的方式。然后获取该列表的python字符串表示并将其发送到服务器。您没有在服务器端执行任何操作以确保获得完整的消息。然后使用
eval
来解释在客户机上创建的字符串。这是一种非常危险的做法,因为您的同龄人基本上可以指示python解释器做任何事情

另外,您的
send\u con\u请求
正在调用
len(id)
,这根本不起作用,因为
id
是python内置的,它不提供
len方法。我想应该是
len(conv_id)

无论如何,你应该修改你的协议。使用
struct
工具创建所需的正确二进制字符串。有很多种可能的方法来构造这个,但这里有一种。在客户端,创建一个固定长度的报头,该报头标识您正在发送的请求类型以及剩余“有效负载”字节的长度。您将首先使用
str.encode
将字符串(用户名或任何内容)转换为字节

import struct

# ProtoHeader encodes a 16 bit request identifer, plus a 32 bit payload
# length. A protocol data unit consists of this 6-byte header followed by 
# payload bytes (which will vary according to the request)
ProtoHeader = struct.Struct("!HI")

LoginRequest = 1
SomeOtherRequest = 2
...

def format_login_request(username):
    """ Create a protocol block containing a user login request.
        Return the byte string containing the encoded request """
    username_bytes = username.encode()
    proto_block = ProtoHeader.pack(LoginRequest, len(username_bytes)) + username_bytes
    return proto_block

...

conn.sendall(format_login_request(username))
在服务器端,您将首先收到固定长度的报头(它告诉您请求类型是什么以及存在多少其他有效负载字节)。然后接收剩余的字节,确保得到的字节数正好是这么多
socket.recv
不保证您将从对等方接收在任何特定
send
中发送的字节数。它确实保证您将以正确的顺序获得它们,因此您必须继续接收,直到您准确获得您期望的数字。这就是为什么将固定长度的字节字符串作为头并对可变长度有效负载中预期的字节数进行编码非常重要

服务器的外观如下所示:

import struct

ProtoHeader = struct.Struct("!HI")
LoginRequest = 1

def receive_bytes(conn, count):
    """ General purpose receiver:
        Receive exactly @count bytes from @conn """
    buf = b''
    remaining = count
    while remaining > 0:
        # Receive part or all of data
        tbuf = conn.recv(remaining)
        tbuf_len = len(tbuf)
        if tbuf_len == 0:
            # Really you probably want to return 0 here if buf is empty and
            # allow the higher-level routine to determine if the EOF is at
            # a proper message boundary in which case, you silently close the
            # connection. You would normally only raise an exception if you 
            # EOF in the *middle* of a message.
            raise RuntimeError("end of file")
        buf += tbuf
        remaining -= tbuf_len
    return buf

def receive_proto_block(conn):
    """ Receive the next protocol block from @conn. Return a tuple of
        request_type (integer) and payload (byte string) """

    proto_header = receive_bytes(conn, ProtoHeader.size)
    request_type, payload_length = ProtoHeader.unpack(proto_header)
    payload = receive_bytes(conn, payload_length)
    return request_type, payload

...

request_type, payload = receive_proto_block(conn)
if request_type == LoginRequest:
    username = payload.decode()