套接字基础与UDP通信

套接字和UDP

   套接字是网络中不同主机上的应用进程之间的双向通信的端点。每个套接字由一个IP地址和一个端口号组成。套接字采用客户机-服务器架构。服务器监听指定的端口等待客户的请求。服务器收到请求后,接受来自客户机套接字的连接,完成客户机与服务器的连接。小于1024的端口已经被占用,因此我们可选用的端口号范围为(1024,65535)。
   UDP是一种只提供了无连接通信,且不对传送的数据包进行可靠性保证的传输层协议。UDP无需在客户机和服务器之间建立连接,客户机向服务器发送请求报文,服务器接收请求报文,向客户机发送响应报文,关闭套接字连接,客户机接受响应报文。

Python实现套接字编程

   Python中提供了socket模块用于套接字编程,socket方法可以直接创建一个套接字,需要两个参数协议(AF_INET:IPV4,AF_INET6:IPV6)和套接字类型(SOCK_STREAM:TCP协议,SOCK_DGRAM:UDP协议)。同时服务器端需要用.bind()方法绑定主机IP和端口号。使用UDP发送数据时只能发送ASCII编码的数据,并且发送的数据必须是字节类型,所以在发送数据时可以使用.encode()方法改变字节编码。.sendto()和.recvfrom()方法用来发送和接收数据并且需要设置最大的字节数。

AA

了解Ping命令

   Ping是一种计算机网络工具,用来测试数据包能否发送到指定的主机。其原理是向目标主机发送请求报文,并等待接受响应报文,通过发送多个报文,可以计算丢包率和网络实验。
   可利用Windows的命令行程序(Win+R,输入cmd即可)进行Ping命令。
   (1)Ping谷歌官网(不可达,数据包丢失)
Ping谷歌官网
  (2)Ping百度官网
Ping百度官网
  (3)ping本主机
Ping本主机
  注:如何查看本主机IP:在命令行程序中输入 ipconfig /all即可
如何查看主机IP

服务器端程序

# UDP服务器程序:UDPServer.py
# 服务器IP:192.168.0.106
# 客户机IP:192.168.0.103
import random
from socket import *
serverSocket = socket(AF_INET, SOCK_DGRAM)    # 创建服务器套接字
serverSocket.bind(('', 6121))                 # 绑定服务器套接字和端口号
print("服务器已启动......")
while True: // 等待客户机的请求
    rand = random.randint(0, 10)    # 生成随机数,用于模拟概率丢包/超时
    message, address = serverSocket.recvfrom(2048)    # 接收客户机的请求报文
    print("报文 '",message.decode(), "' 接收成功", sep="")
    if rand < 4:     # 以一定的概率模拟超时
        print()
        continue
    serverSocket.sendto(message.decode().upper().encode(), address)     # 发送响应报文
    print("报文 '", message.decode().upper(), "' 发送成功\n", sep="")      # 打印响应报文发送成功

  服务器端程序代码解析:生成服务器套接字 serverSocket,绑定服务器主机与指定的端口号(此处端口号选用6121),服务器保持等待,等待客户机请求。接收到客户机报文后,以一定概率rand模拟超时丢包,如果rand小于4则让服务器不发生响应报文;否则服务器回传响应报文。

客户机端程序

# UDP客户机程序:UDPClient.py
# 服务器IP:192.168.0.106
# 客户机IP:192.168.0.103
import time
import numpy as np
from socket import *
# 客户机端套接字设置
clientSocket = socket(AF_INET, SOCK_DGRAM)   # 创建客户机套接字
clientSocket.settimeout(1)  # 设置的最大等待时间
serverName = "192.168.0.106"       # 服务器主机
message = ["lxy","hny","python","test","deeplearning","net","face","love","hahaha","lalala"]    # 发送10个Ping报文
success = []      # 存放接收成功的Ping报文对应的时延
print("正在 Ping",serverName,"具有 51 字节的数据:")
# 发送报文
for i in range(10):
    clientSocket.sendto(message[i].encode(), (serverName,6121))   # 发送Ping报文
    start = time.perf_counter()    # 计时开始
    try:
        modifiedMessage,serverAddress = clientSocket.recvfrom(2048)   # 等待接收响应Pong报文
        end = time.perf_counter()  # 计时结束
        print("来自 ", serverName, " 的回复:报文='", modifiedMessage.decode(),"', 字节=",len(message[i]), ", 时延RTT=", end - start, "s。", sep="")
        success.append(end-start)   # 将成功接收响应报文对应的时延保存
    except :     # 异常抛出,程序继续运行
        print("[Error]:请求超时")
clientSocket.close()    # 关闭客户机套接字

## 打印 Ping 的统计信息
print("\n",serverName,"的 Ping 统计信息:\n    数据包:已发送=10 ,已接受=%d ,丢失=%d (%d%% 丢失)"%(len(success),10-len(success),100*(1-len(success)/10)))
if len(success)>0:
    print("往返行程的估计时间(以秒为单位):\n    最短=%6fs,最长=%6fs,平均=%7fs"%(min(success),max(success),np.mean(success)),sep="")

  客户机端程序代码解析:生成客户机套接字,基于服务器主机(使用“127.0.0.1”或者使用IP:192.168.0.103)和端口号向服务器发送10次Ping报文,保持静默等待服务器回复;若客户机能够接收到响应报文则计算时延和输出报文,若不能接收到Pong报文则输出“请求超时”;发送10次Ping报文后,统计10次Ping报文的丢包率和时延。
  注:程序中使用time.perf_counter()计时,而不是time.time()是因为前者精度更高。

运行程序步骤

(1)运行服务器程序UDPServer.py,保持服务器在正常工作中,即不能终止程序。
(2)运行客户机程序UDPClient.py

测试运行结果

(1)客户机程序和服务器程序在同一主机上运行(左为服务器控制台输出,右为客户机控制台输出)
在这里插入图片描述 在这里插入图片描述
(2)客户机程序和服务器程序在不同主机上运行(左为服务器控制台输出,右为客户机控制台输出)
在这里插入图片描述 在这里插入图片描述

问题及解决方法

(1)报错:Socket.gaierror: [Error 11001] getaddrinfo failed
  主机IP有误,应该选用主机IP而不是主机名
(2)报错:Socket.timeout: timed out
  报错的原因是settimeout()函数遇到错误是会直接报错而终止程序的运行的,所以应该加上try……except将异常抛出而不让该函数报错,影响程序的正常运行。
(3)客户机向服务器发送10个Ping报文中,若第一个报文是被服务器忽略而不回复时,客户机程序不会运行下去。
  settimeout(1)设置最大等待时间函数的定义位置不准确,一开始是将该定义放在了recvfrom()函数后,正确的做法应该将这个超时异常提前定义。

代码提取

  相关代码可在https://github.com/Hny1216/Socket_UDP.git上提取

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值