Python 使用 sockets 的 recv 方法

-1 投票
3 回答
1712 浏览
提问于 2025-04-17 21:31

我在用Python编写一个服务器-客户端的程序,使用的是套接字(socket)。当我作为服务器接收到客户端发来的数据时,我使用了接收函数:

someSocket.recv()

请问,有可能接收到一个我不知道是什么的对象吗?还是说我必须要记录一下从套接字接收到的数据大小?

3 个回答

0

套接字(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个字节,如果你想发送更多的数据,就需要用循环结构来处理。个人来说,我觉得套接字的使用太底层了,所以我用这个简单的库来满足我的网络需求。它声称适合游戏,但其实可以用于任何用途。

0

根据你的评论,我明白你想知道接收到的数据是整数还是字符串。在接收到数据后,你可以把它存储到一个变量里。然后你可以使用一些方法,比如 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

你可以把这两种方法结合起来,创建一个新的方法来完成所有这些判断。

1

为了简单的交流,你需要某种形式的数据序列化。对于简单的通信,我通常会把套接字(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) 来检查响应是否是一个整数。

效率:这些解决方案是通过文本数据进行传输的,但别担心,过度优化网络通信是很少需要的。这些解决方案非常适合用来搭建简单的客户端-服务器应用。

撰写回答