【问题标题】:Send/receive Packets with TCP sockets使用 TCP 套接字发送/接收数据包
【发布时间】:2013-07-04 05:03:29
【问题描述】:

最近,我设法在我的 PC 和 Raspberry Pi 上创建了套接字,以实现两个设备之间的通信。目前,客户端能够自动向服务器发送消息。我想知道,是否可以修改脚本以发送 tcp 数据包而不是纯文本消息,因为我非常希望将来使用我的 PC 来控制树莓派,而无需 ssh/etc。

我查看了一些示例,但由于我在编写自己的脚本/代码方面没有太多经验,因此我不太确定如何去做。如果有人可以通过解释和一些例子指导我正确的方向,我将不胜感激。

这里是我目前正在运行的服务器/客户端脚本:

客户:

import socket   
import sys  
import struct
import time

#main function
if __name__ == "__main__":

    if(len(sys.argv) < 2) :
        print 'Usage : python client.py hostname'
        sys.exit()

    host = sys.argv[1]
    port = 8888

#create an INET, STREAMing socket
try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
    print 'Failed to create socket'
    sys.exit()

print 'Socket Created'

try:
    remote_ip = socket.gethostbyname( host )
    s.connect((host, port))

except socket.gaierror:
    print 'Hostname could not be resolved. Exiting'
    sys.exit()

print 'Socket Connected to ' + host + ' on ip ' + remote_ip

#Send some data to remote server
message = "Test"

try :
    #Set the whole string
    while True:
        s.send(message)
        print 'Message sent successfully'
        time.sleep(1)
        print 'Sending...'
except socket.error:
    #Send failed
    print 'Send failed'
    sys.exit()

def recv_timeout(the_socket,timeout=2):
    #make socket non blocking
    the_socket.setblocking(0)

    #total data partwise in an array
    total_data=[];
    data='';

    #beginning time
    begin=time.time()
    while 1:
        #if you got some data, then break after timeout
        if total_data and time.time()-begin > timeout:
            break

        #if you got no data at all, wait a little longer, twice the timeout
        elif time.time()-begin > timeout*2:
            break

        #recv something
        try:
            data = the_socket.recv(8192)
            if data:
                total_data.append(data)
                #change the beginning time for measurement
                begin=time.time()
            else:
                #sleep for sometime to indicate a gap
                time.sleep(0.1)
        except:
            pass

    #join all parts to make final string
    return ''.join(total_data)

#get reply and print
print recv_timeout(s)

s.close()

服务器:

import socket
import sys
from thread import *

HOST = ''   # Symbolic name meaning all available interfaces
PORT = 8888

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'

try:
    s.bind((HOST, PORT))
except socket.error , msg:
    print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
    sys.exit()

print 'Socket bind complete'

s.listen(10)
print 'Socket now listening'

#Function for handling connections
def clientthread(conn):
    #Sending message to connected client
    conn.send('Welcome to the server. Receving Data...\n') #send only takes string

    #infinite loop so that function do not terminate and thread do not end.
    while True:

        #Receiving from client
        data = conn.recv(1024)
        reply = 'Message Received at the server!\n'
        print data
        if not data:
            break

        conn.sendall(reply)

    conn.close()

#now keep talking with the client
while 1:
    #wait to accept a connection
    conn, addr = s.accept()
    print 'Connected with ' + addr[0] + ':' + str(addr[1])

    #start new thread
    start_new_thread(clientthread ,(conn,))

s.close()

【问题讨论】:

    标签: python sockets tcp client-server packet


    【解决方案1】:

    socket.socket(socket.AF_INET, socket.SOCK_STREAM) 已经创建了一个连接,该连接在两台机器之间提供了可靠的字节流。这使用 TCP,它位于 IP 和以太网之上。后两者是基于包的,而 TCP 在其上创建连续字节流。它还添加了一些错误检查和纠错功能,因此非常可靠。

    老实说,我不明白你想用所谓的“发送数据包”来实现什么。您不想做的是自己创建 TCP 的实现,因为这是一项不平凡的任务,因此发送 RAW 数据包已被淘汰。一般来说,即使使用 TCP 也已经是比较低级的了,除非真的必要,否则应该避免使用。

    使用例如ZeroMQ 您将获得一个基于消息的接口,为您完成所有传输。它在 TCP(或其他传输)之上执行此操作,并为例如添加更多纠错。断开连接。在那里,您也有类似“数据包”的东西,但它们与需要多少 TCP 或 IP 数据包才能在下面发送它无关。如果您不想实现特定协议,我建议您使用此框架而不是低级 TCP 套接字。

    另一个简单的替代方法是使用 HTTP,Python 中也有现有的代码。缺点是总是一方发起一些通信,另一方只回复。如果您想要某种主动通知,您要么必须进行投票,要么使用延迟回答等技巧。

    【讨论】:

      【解决方案2】:

      您已经在发送数据包——这些数据包恰好包含文本数据。尝试查看标准库中的 pickle 和 pyro

      【讨论】:

      • 我正在阅读 RAW 套接字以及它们如何在 TCP/IP 中发送/接收 RAW 数据包,并且需要在脚本中手动指定 tcp 和 ip 标头。将数据包发送到树莓派以控制其某些功能是否是更好的方法?抱歉,如前所述,我对套接字和数据包没有太多经验。我正在运行的脚本是标准套接字,并且“消息”有效负载是通过 TCP 传输的,是否可以修改部分脚本以发送数据包(而不是作为文本数据)来完成这项工作?
      • 另外,socket.error 处理是检查发送数据错误的唯一方法吗?还是有其他方法可以进行错误检查,例如在服务器接收到数据时,它会执行冗余检查以确保在传输过程中没有数据丢失?
      猜你喜欢
      • 2021-10-23
      • 2019-05-07
      • 2016-05-09
      • 2013-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-12
      • 1970-01-01
      相关资源
      最近更新 更多