使用TCP套接字发送/接收数据包

6
最近,我成功在我的电脑和树莓派上创建了套接字以实现两个设备之间的通信。目前,客户端能够自动向服务器发送消息。我想知道是否可能修改脚本以发送TCP数据包而不是纯文本消息,因为我将来非常希望使用我的电脑控制树莓派而无需使用ssh等方式。
我查看了一些示例,但由于我没有写自己的脚本/代码的经验,我不太确定如何处理这个问题。如果可能的话,我会感激有人能够指导我正确的方向,并提供一些解释和示例。
无论如何,以下是我目前正在运行的服务器/客户端脚本:
客户端:
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()
2个回答

5

socket.socket(socket.AF_INET, socket.SOCK_STREAM)创建了一个可靠的字节流连接,用于在两台计算机之间传输数据。它使用TCP协议,该协议位于IP和以太网之上。前两者是基于包的,而TCP在其之上创建了一条连续的字节流。它还添加了一些错误检查和纠正功能,因此非常可靠。

我不明白您所说的“发送数据包”的目的是什么。您不希望自己创建TCP的实现,因为这是一项非常复杂的任务,所以发送原始数据包是不可行的。通常情况下,即使使用TCP也已经相对低级,并且应该尽可能避免使用,除非真正必要。

例如使用ZeroMQ,您可以获得一个基于消息的接口,它为您执行所有传输操作。它在TCP(或其他传输方式)之上进行操作,并增加了更多的错误检查功能,以处理例如断开连接的情况。在那里,您也有类似“数据包”的东西,但是这些独立于在底层发送它所需的TCP或IP数据包数量。如果您不想实现特定的协议,我建议您使用此框架,而不是使用低级别的TCP套接字。

另一个简单的选择是使用HTTP,Python中也有现成的代码。缺点是它总是有一方发起通信,而另一方只能回复。如果您想要某种主动通知,您需要轮询或使用诸如延迟回复之类的技巧。


1

你已经在发送数据包 - 目前这些数据包恰好包含文本数据。尝试查看标准库中的pickle以及pyro


我正在研究RAW套接字及其如何在TCP/IP中发送/接收RAW数据包,需要在脚本中手动指定TCP和IP头。相比而言,将数据包发送到树莓派以控制其某些功能是否更好呢? 很抱歉,由于我的套接字和数据包经验不多,我运行的脚本是标准套接字,并且“消息”有效负载通过TCP传输,是否有可能修改脚本的某些部分,以便使用数据包(而不是文本数据)来完成该工作? - intensified
此外,socket.error处理是否是检查发送数据错误的唯一方式?或者我们还有其他方法可以进行错误检查,例如当服务器接收到数据时,它会执行冗余检查以确保在传输过程中没有丢失数据? - intensified

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接