MySQLi
намного безопаснее, чем MySQL
, который в любом случае устарел. Вот почему вы должны придерживаться MySQLi
, а также вы не можете смешивать их, поскольку они оба разные.
TCP / IP - это протокол на основе потока , а не протокол на основе сообщений . Нет никакой гарантии, что каждый send()
вызов одним одноранговым узлом приводит к единственному вызову recv()
другим одноранговым узлом, получающему точные данные, - он может получать кусочек данных, разделенный на несколько вызовов recv()
, из-за пакета фрагментация.
Чтобы дифференцировать границы сообщений, вам нужно определить свой собственный протокол на основе протокола TCP. Затем, чтобы прочитать сообщение, вы продолжаете называть recv()
до тех пор, пока не прочитаете целое сообщение или не появится ошибка.
Один простой способ отправки сообщения - префикс каждого сообщения с его длиной. Затем, чтобы прочитать сообщение, сначала прочитайте длину, затем вы прочтете, что много байтов. Вот как вы можете это сделать:
def send_msg(sock, msg):
# Prefix each message with a 4-byte length (network byte order)
msg = struct.pack('>I', len(msg)) + msg
sock.sendall(msg)
def recv_msg(sock):
# Read message length and unpack it into an integer
raw_msglen = recvall(sock, 4)
if not raw_msglen:
return None
msglen = struct.unpack('>I', raw_msglen)[0]
# Read the message data
return recvall(sock, msglen)
def recvall(sock, n):
# Helper function to recv n bytes or return None if EOF is hit
data = b''
while len(data) < n:
packet = sock.recv(n - len(data))
if not packet:
return None
data += packet
return data
Затем вы можете использовать функции send_msg
и recv_msg
для отправки и получения целых сообщений, и у них не будет проблем с разбиением пакетов или объединены на сетевом уровне.
Вам может потребоваться несколько раз вызвать conn.recv () для получения всех данных. При вызове его один раз не гарантируется получение всех отправленных данных из-за того, что потоки TCP не поддерживают границы кадров (т. Е. Они работают только как поток необработанных байтов, а не структурированный поток сообщений) .
См. этот ответ для другого описания проблемы.
Обратите внимание, что это означает, что вам нужен какой-то способ узнать, когда вы получили все данные , Если отправитель всегда будет отправлять ровно 8000 байт, вы можете подсчитать количество полученных байтов до сих пор и вычесть из 8000, чтобы узнать, сколько осталось получить; если данные имеют переменный размер, существуют различные другие методы, которые могут использоваться, например, когда отправитель отправляет заголовок с номерами байтов перед отправкой сообщения или если он отправляет текст ASCII, вы можете искать символ новой строки или NUL.
Принятый ответ хорош, но он будет очень медленным с большими файлами -string - это неизменный класс, это означает, что каждый объект будет создан каждый раз, когда вы используете знак +
, используя list
в качестве структуры стека будет больше эффективный.
Это должно работать лучше
while True:
chunck = s.recv(10000)
if not chunck:
break
fragments.append(chunck)
print "".join(fragments)
Вариант с использованием функции генератора (который я считаю более pythonic):
def recvall(sock, buffer_size=4096):
buf = sock.recv(buffer_size)
while buf:
yield buf
if len(buf) < buffer_size: break
buf = sock.recv(buffer_size)
# ...
with socket.create_connection((host, port)) as sock:
sock.sendall(command)
response = b''.join(recvall(sock))
recvall
должно давать содержимое каждого буфера, полученного независимо от размера, если он не пуст.
– yoniLavi
6 November 2017 в 14:45
Изменение кода Адама Розенфилда:
import sys
def send_msg(sock, msg):
size_of_package = sys.getsizeof(msg)
package = str(size_of_package)+":"+ msg #Create our package size,":",message
sock.sendall(package)
def recv_msg(sock):
try:
header = sock.recv(2)#Magic, small number to begin with.
while ":" not in header:
header += sock.recv(2) #Keep looping, picking up two bytes each time
size_of_package, separator, message_fragment = header.partition(":")
message = sock.recv(int(size_of_package))
full_message = message_fragment + message
return full_message
except OverflowError:
return "OverflowError."
except:
print "Unexpected error:", sys.exc_info()[0]
raise
Я бы, однако, очень хотел использовать оригинальный подход.
Вы можете использовать его как: data = recvall(sock)
def recvall(sock):
BUFF_SIZE = 4096 # 4 KiB
data = b''
while True:
part = sock.recv(BUFF_SIZE)
data += part
if len(part) < BUFF_SIZE:
# either 0 or end of data
break
return data
sock.recv()
. Это будет зависать, поскольку больше не поступает данных. Если длина part
меньше, чем длина RECV_BUFFER
, тогда код может безопасно вырваться из цикла.
– SomeGuyOnAComputer
4 December 2015 в 00:15
Exception: Socket EOF trying to recv 4 bytes
Я использую следующее: pastebin.com/raw.php?i=AvdN5RyW – user2585107 16 July 2013 в 06:22return None
вместо повышения исключения при завершении потока. – Adam Rosenfield 16 July 2013 в 21:42packet
быть.decode()
до добавления его вdata
илиrecv()
может принимать как байты, так и строки? – Siemkowski 21 September 2017 в 08:49