Python 使用 sockets 的 recv 方法
我在用Python编写一个服务器-客户端的程序,使用的是套接字(socket)。当我作为服务器接收到客户端发来的数据时,我使用了接收函数:
someSocket.recv()
请问,有可能接收到一个我不知道是什么的对象吗?还是说我必须要记录一下从套接字接收到的数据大小?
3 个回答
套接字(Sockets)只发送和接收字节对象。你可以通过pickle来发送对象(不过要记住,pickle不安全)。你可以用isinstance()来检查对象的类型:
data= sock.recv(1024)
obj= pickle.loads(data)
isInt= isinstance(obj, int)
如果你想把字节转换成字符串,你需要解码这些字节:
data= sock.recv(1024)
strdata= data.decode('utf-8')
接收数据时,最好每次接收1024个字节,如果你想发送更多的数据,就需要用循环结构来处理。个人来说,我觉得套接字的使用太底层了,所以我用这个简单的库来满足我的网络需求。它声称适合游戏,但其实可以用于任何用途。
根据你的评论,我明白你想知道接收到的数据是整数还是字符串。在接收到数据后,你可以把它存储到一个变量里。然后你可以使用一些方法,比如 isdigit()
和 isinstance 来判断它是字符串、整数还是浮点数。
举个例子:
Test = "123"
if Test.isdigit() == True:
print "Test is an integer"
else:
print "Test is not an integer"
如果你想知道它是不是浮点数,可以尝试使用 isinstance。
>>> x = 123
>>> isinstance(x, int)
True
>>> y = 123.01
>>> isinstance(y, float)
True
你可以把这两种方法结合起来,创建一个新的方法来完成所有这些判断。
为了简单的交流,你需要某种形式的数据序列化。对于简单的通信,我通常会把套接字(socket)当作一个文件来使用,然后用一些简单的文本协议,比如pickle或json。你可以选择使用pickle,或者如果你想发送人类可读的文本,那么就发送单行的、不换行的json,并用换行符结束每个对象。对于Python来说,pickle给你更多的灵活性,因为json在什么数据被认为是有效的方面有一些限制。
下面是基于pickle和json的简单客户端-服务器示例:
client.py:
import socket, pickle
def socket_to_file(sock):
try:
sock.settimeout(15)
return sock.makefile()
finally:
sock.close()
if __name__ == '__main__':
sock = socket.create_connection(('localhost', 3005))
sock = socket_to_file(sock)
try:
request = {
'param0': True,
'param2': 'sztringecske',
}
print 'Sending request: %s' % (request,)
pickle.dump(request, sock)
sock.flush() # important!!!
response = pickle.load(sock)
print 'Received response: %s' % (response,)
finally:
sock.close()
server.py:
import socket, pickle
def socket_to_file(sock):
try:
client_sock.settimeout(15)
return sock.makefile()
finally:
sock.close()
if __name__ == '__main__':
listen_sock = socket.socket()
try:
listen_sock.bind(('', 3005))
listen_sock.listen(10)
client_sock, client_addr = listen_sock.accept()
finally:
listen_sock.close()
try:
client_sock = socket_to_file(client_sock)
request = pickle.load(client_sock)
print 'Request: %s' % (request,)
response = 'My smart response.'
print 'Response: %s' % (response,)
pickle.dump(response, client_sock)
client_sock.flush()
finally:
client_sock.close()
json_client.py:
import socket, json
def socket_to_file(sock):
try:
sock.settimeout(15)
return sock.makefile()
finally:
sock.close()
if __name__ == '__main__':
sock = socket.create_connection(('localhost', 3005))
sock = socket_to_file(sock)
try:
request = {
'param0': True,
'param2': 'sztringecske',
}
print 'Sending request: %s' % (request,)
sock.write(json.dumps(request))
sock.write('\n')
sock.flush() # important!!!
response = json.loads(sock.readline())
print 'Received response: %s' % (response,)
finally:
sock.close()
json_server.py:
import socket, json
def socket_to_file(sock):
try:
client_sock.settimeout(15)
return sock.makefile()
finally:
sock.close()
if __name__ == '__main__':
listen_sock = socket.socket()
try:
listen_sock.bind(('', 3005))
listen_sock.listen(10)
client_sock, client_addr = listen_sock.accept()
finally:
listen_sock.close()
try:
client_sock = socket_to_file(client_sock)
request = json.loads(client_sock.readline())
print 'Request: %s' % (request,)
response = 'My smart response.'
print 'Response: %s' % (response,)
client_sock.write(json.dumps(response))
client_sock.write('\n')
client_sock.flush()
finally:
client_sock.close()
如何判断你收到的数据是什么类型?最好的办法是你不需要去判断。通过上述解决方案,你可以发送复杂的对象,比如 {'command': 'delete', 'delete_param': 'delete_specific_param' }
。如果你定义你的协议,使得发送到服务器的消息总是包含 command
这个键,那么服务器就可以始终检查这个键,并根据实际的命令来解释其余的数据。如果你仍然坚持发送简单的对象,比如 int
,那么在收到响应后,你可以简单地使用 isinstance(response, int)
来检查响应是否是一个整数。
效率:这些解决方案是通过文本数据进行传输的,但别担心,过度优化网络通信是很少需要的。这些解决方案非常适合用来搭建简单的客户端-服务器应用。