实验二《套接字基础与UDP通信》

一、实验目的

熟悉基于 Python 进行 UDP 套接字编程的基础知识,掌握使用 UDP 套接字发送和接收数据包, 以及设置正确的套接字超时,了解Ping 应用程序的基本概念,并理解其在简单判断网络状态,例如计算数据包丢失率等统计数据方面的意义。

二、实验内容

1. 操作系统附带的标准ping命令使用ICMP进行通信,本实验要求学生编程实现一个简单的,非标准的,基于UDP 进行通信的ping程序。学生需要用 Python 编写一个Ping客户端。客户 端程序发送一个ping报文,然后接收一个从已经提供的服务器上返回的对应 pong报文,并计算出从该客户发送ping报文到接收到pong 报文为止的往返时延(Round-Trip Time,RTT)。

2. 在客户端程序一次执行过程中,学生编写的的ping 客户端程序需经UDP 向服务器发送10个ping报文。对于每个报文,当对应的 pong 报文返回时,客户端程序要确认并打印输出 RTT 值;在整个执行过程中,客户端程序需要考虑分组丢失情况,客户端最多等待1秒,超过该时长则打印丢失报文。

三、实验方法

UDP 作为一种传输层协议,只提供了无连接通信,且不对传送的数据包进行可靠性保证,因此 只适合于一次传输少量数据的应用场景,如果在传输过程中需要保证可靠性,则这种可靠性应该由 应用层负责。本实验创建的 Ping 程序正是一种不需要保证可靠性的程序,并需要利用这种不可靠性来测量网络的联通情况。

虽然UDP不保证通信的可靠性,包到达的顺序,也不提供流量控制。但正是因为UDP 的控制选 项较少,所以在数据传输过程中延迟小、数据传输效率高, 一些对可靠性要求不高,但对性能等开销更敏感的应用层协议会选择基于UDP进行实现,常见的使用UDP的应用层协议包括 TFTP、SNMP、NFS、DNS、BOOTP等,通常占用53 (DNS) 、69(TFTP) 、161(SNMP)等端口。基于UDP 的无连接客户/服务器在 Python 实现中的工作流程如下:

1. 首先在服务器端通过调用 socket() 创建套接字来启动一个服务器;

2. 服务器调用 bind()指定服务器的套接字地址,然后调用 recvfrom()等待接收数据。

3. 在客户端调用 socket()创建套接字,然后调用 sendto() 向服务器发送数据。

4. 服务器接收到客户端发来的数据后,调用 sendto() 向客户发送应答数据,

5. 客户调用 recvfrom()接收服务器发来的应答数据。

6. 一旦数据传输结束,服务器和客户通过调用 close() 来关闭套接字。

注意在不同的计算机语言实现中,上述调用的名字和具体工作流程可能略有不同。基于Python的 UDP 程序工作详细流程如下图所示。

基于Python进行UDP消息的接收操作时,Python程序将工作在阻塞状态,即未收到数据包时,Python程序将挂起等待而不会继续执行。如果程序运行中网络连接出现了问题,导致数据包无法及时到达,这种阻塞式的工作模式将会严重的干扰程序的执行。为了解决这个问题,Python的套接字通信库提供了一种“超时”机制来防止程序卡死。在 Python套接字程序中,套接字对象提供了一个 settimeout() 方法来限制 recvfrom() 函数的等待时间,当 recvfrom() 函数阻塞等待超过这个时 间(一般称为“超时时间”)后仍然没有收到数据时,程序将会抛出一个异常来说明发生了等待数据接收超时事件。在编写Python网络通信程序时,可以利用这个机制来判断是否接收数据超时。

四、实验步骤

1.根据附件中的程序示例写出客户端和服务端程序:

2.在程序运行结束时,计算所有 ping消息的最小、最大和平均 RTT, 并计算丢包 率(丢失数据包在总数据包中所占有的百分比):

    先设置五个值:max_rtt用于记录最大rtt值,min_rtt用于记录最小rtt值,sum_rtt用于记录rtt值的和(丢包的不算),count用于记录成功传输的包数,timeout1用于记录丢包数。

再设置每一个的计算方法:

最后打印输出计算好的值:

五、实验结果

1.服务端输出信息:

2.客户端信息:

六、实验结论

1.服务端:

from socket import *
import random
import time

# 创建一个UDP套接字
serverSocket = socket(AF_INET, SOCK_DGRAM)

# 将套接字绑定到特定的IP地址和端口
serverSocket.bind(('127.0.0.1', 12000))

while True:
    rand = random.randint(0, 10)

    # 接收消息及客户端地址
    message, address = serverSocket.recvfrom(1024)
    print("receive", message, "from", address)

    # 处理消息,转为大写
    message_upper = message.upper()

    # 根据随机条件模拟响应
    if rand > 4:
        rand2 = random.randint(0, 10)  # 生成随机延迟时间
        time.sleep(rand2 * 0.1)  # 模拟处理时间

        # 将处理后的消息发送回客户端
        serverSocket.sendto(message_upper, address)
        print("Send response", message_upper, "to", address)

其中bind函数将套接字绑定至某个主机的接口,recv函数返回服务器发送的信息长度。

2.客户端:

from multiprocessing.connection import Client
from socket import *
import random
import time

serverSocket = socket(AF_INET, SOCK_DGRAM)
serverSocket.settimeout(1)

address = ('127.0.0.1', 12000)


def client(message1, address):
    start = time.time()
    serverSocket.sendto(message1, address)

    try:
        message2, address = serverSocket.recvfrom(1024)
        end = time.time()
        rtt = end - start
        print(message2, address, rtt)
        return rtt
    except timeout:
        print("time out")
        return -1


max_rtt = 0
min_rtt = 1
sum_rtt = 0
count = 0
timeout1 = 0

for x in range(0, 10):
    message = x
    x1 = str(message)
    message1 = x1.encode()

    rtt = client(message1, address)

    if rtt != -1:
        sum_rtt = sum_rtt + rtt
        count = count + 1
        if rtt > max_rtt:
            max_rtt = rtt
        if rtt < min_rtt:
            min_rtt = rtt
    else:
        timeout1 = timeout1 + 1

print("max Round-Trip Time is " + str(max_rtt) + " Second")
print("min Round-Trip Time is " + str(min_rtt) + " Second")
print("average Round-Trip Time is " + str(sum_rtt / count) + " Second")
print("package loss rate is " + str(timeout1 * 10) + "%")

其中client函数用于获取rtt值,若包丢失则值为-1。address的值为服务端固定的主机号和端口号。

七、实验小结

本次实验的主要内容为UDP的套接字通信。通过本次实验我熟悉了基于Python进行 UDP套接字编程的基础知识,并且掌握使用UDP套接字发送和接收数据包,以及设置正确的套接字超时。通过模仿ping命令,我了解了ping 应用程序的基本概念,并理解了其在简单判断网络状态,例如计算数据包丢失率等统计数据方面的意义。我在本次实验中遇到了两个问题,第一个是不知道如何将服务端与客户端相连,后来发现只需要将客户端的address设置为服务端绑定的主机号和端口号即可;第二个问题是在计算平均rtt值时,一开始我忽略了丢包的rtt被置为-1的情况,导致第一次计算出来的平均rtt值为负值。看到值为负时我才反应过来,于是将累加语句放到判断条件里,又加了一个计数器count来记录未丢包数,最后输出sum_rtt的值除以count的值,这才解决了问题。

  • 35
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值