基于udp协议的服务器和客户端以及特殊点

发布时间 2023-10-24 11:41:22作者: songjunwan

基于udp协议的服务器和客户端

基础版的格式以及特殊点

服务器代码如下

import socket
#udp的服务器(server)的格式
server = socket.socket(type=socket.SOCK_DGRAM)

#给udp服务器绑定IP地址和端口
server.bind(('172.17.8.49', 8080))

#需不需要监听?
#udp协议不要建立连接,直接发


#recvfrom
#udp收取文件的格式
data, addr = server.recvfrom(1024)

print(data)

#udp发送格式
server.sendto(data.upper(),addr)#这里的第一个是要发送的数据,第二个是发送的地址

udp服务器相对于tcp的服务器少了监听的过程以及发送和收取的格式和tcp的不一样

udp的发送和收取格式分别为:

接收:recvfrom(1024)、发送:sendto(data.upper(),addr)这里的upper()将data这个数据大写以后再发送,addr是发送的地点

同时它要按照socket.SOCK_DGRAM这个格式来表达udp的对象

客户端代码如下

import socket

client = socket.socket(type=socket.SOCK_DGRAM)

#直接发
#这里的第一个参数是数据部分,第二个参数是客户端地址
client.sendto(b'abc',('172.17.8.49',8080))#这个数据发送到服务器

data = client.recvfrom(1024)#这里接收

print(data)#这里来输出接收到的数据

这里的接收格式也是recvfrom(1024) , 这里的发送也是有所不同sendto(b'abc',('172.17.8.49',8080))这里面的b'abc'是按照bytes格式来写的,后面的是发送的IP地址和端口的元组

略微修改版

这个基础版只能搞bytes的格式有些局限,现在略微升级一下,使用utf-8编码来发送想要发送的数据

服务器代码


import socket

# udp的服务器(server)的格式
server = socket.socket(type=socket.SOCK_DGRAM)

# 给udp服务器绑定IP地址和端口
server.bind(('172.17.8.49', 8080))

# 需不需要监听?
# udp协议不要建立连接,直接发


# recvfrom
# udp收取文件的格式
data, addr = server.recvfrom(1024)

print(data.decode('utf-8'))

fasong = input('请回复:')  # 这里给客户端回复对应的信息
fasong = fasong.encode('utf-8')  # 这里进行utf-8的编码,方便接收

# udp发送格式
server.sendto(fasong, addr)  # 这里的第一个是要发送的数据,第二个是发送的地址

客户端代码

import socket

client = socket.socket(type=socket.SOCK_DGRAM)


msg = input('发送:')#这里来写需要发给服务器的数据
msg = msg.encode('utf-8')
#直接发
#这里的第一个参数是数据部分,第二个参数是客户端地址
client.sendto(msg, ('172.17.8.49', 8080))
#这里接收来自服务器的数据
data, addr = client.recvfrom(1024)#这一步比较重要因为服务器发过来的包括了数据以及发送方的地址信息

data = data.decode('utf-8')



print(data)#这里打印来自服务器的数据

客户端有一处地方必须要按照data, addr = client.recvfrom(1024)的格式来写,因为它接收到的服务器的数据不只有数据还有服务器的地址信息,所以将数据赋值给data,把地址信息赋值给addr,这么做是为了方便后面的解码

结果如图

客户端

服务端

比较重要的一点udp协议是否有粘包问题?

这里给代码里面加入通信循环来用于验证的服务器和客户端

服务器


import socket
#udp的服务器(server)的格式
server = socket.socket(type=socket.SOCK_DGRAM)

#给udp服务器绑定IP地址和端口
server.bind(('172.17.8.49', 8080))



while True:
    data, addr = server.recvfrom(1024)
    print(data)
#     # udp发送格式
#     server.sendto(data.upper(), addr)  # 这里的第一个是要发送的数据,第二个是发送的地址

客户端

import socket

client = socket.socket(type=socket.SOCK_DGRAM)


while True:
    msg = input('>>:')
    # 直接发
    # 这里的第一个参数是数据部分,第二个参数是客户端地址
    client.sendto(msg.encode('utf-8'), ('172.17.8.49', 8080))  # 这个数据发送到服务器

    client.sendto(b'12', ('172.17.8.49', 8080))
    client.sendto(b'34', ('172.17.8.49', 8080))
    client.sendto(b'56', ('172.17.8.49', 8080))

    data = client.recvfrom(1024)

    print(data)

结果为

通过结果图得知udp不具有粘包问题,具体原因和它的特点有关。udp协议又叫数据报协议,这个协议可以空的数据过去,而tcp就不行,同时在发送数据时这个协议会给每个数据包个头来防止粘包

然后udp丢包的情况如下

这里给客户端改一下

import socket

client = socket.socket(type=socket.SOCK_DGRAM)

while True:
    msg = input('输入:')

    client.sendto(msg.encode('utf-8'), ('172.17.8.49', 8080))

结果如图

丢包的情况就是我的服务器没有开启,但是我的客户端一直给服务器发送数据,这些发送的数据最后都会丢失。这就是丢包

为什么会有丢包的情况呢?因为udp协议的特殊点就在于它不用建立连接就可以使用,所以就会出现服务器没有打开客户端打开发送数据的情况,同理如果我的客户端没有打开,服务器打开并发送数据,它也会出现这个情况。udp这一点就不可靠

互相通信版本同时加入一些判断

服务器

#互相通信版本(pro版本)
import socket

# udp的服务器(server)的格式
server = socket.socket(type=socket.SOCK_DGRAM)


# 给udp服务器绑定IP地址和端口
server.bind(('172.17.8.49', 8080))


while True:
    # recvfrom
    # udp收取文件的格式
    data, addr = server.recvfrom(1024)
    print(f'某某计算机以连接{addr}')#这里可以读取发送方的IP地址
    print(data.decode('utf-8'))

    fasong = input('请回复:')# 这里给客户端回复对应的信息


    jieshu = input('是否结束(yes/no):')#这是判断是否结束用的
    #这里添加判断方便终止连接
    if jieshu == 'yes':
        fasong = fasong.encode('utf-8')  # 这里进行utf-8的编码,方便接收

        # udp发送格式
        server.sendto(fasong, addr)  # 这里的第一个是要发送的数据,第二个是发送的地址
        break

    else:
        fasong = fasong.encode('utf-8')  # 这里进行utf-8的编码,方便接收

        # udp发送格式
        server.sendto(fasong, addr)  # 这里的第一个是要发送的数据,第二个是发送的地址

客户端

#互相通信版本(pro版本)
import socket

client = socket.socket(type=socket.SOCK_DGRAM)

while True:
    msg = input('发送:')  # 这里来写需要发给服务器的数据

    jieshu = input('是否结束(yes/no):')#这是用于判断是否结束用的

    msg = msg.encode('utf-8')

    #这里添加是否结束判读
    if jieshu == 'yes':
        # 直接发
        # 这里的第一个参数是数据部分,第二个参数是客户端地址
        client.sendto(msg, ('172.17.8.49', 8080))
        # 这里接收来自服务器的数据
        data, addr = client.recvfrom(1024)  # 这一步比较重要因为服务器发过来的包括了数据以及发送方的地址信息

        data = data.decode('utf-8')

        print(data)  # 这里打印来自服务器的数据

        break
    else:
        # 直接发
        # 这里的第一个参数是数据部分,第二个参数是客户端地址
        client.sendto(msg, ('172.17.8.49', 8080))
        # 这里接收来自服务器的数据
        data, addr = client.recvfrom(1024)  # 这一步比较重要因为服务器发过来的包括了数据以及发送方的地址信息

        data = data.decode('utf-8')

        print(data)  # 这里打印来自服务器的数据

这里我在循环里面添加了判断语句,同时当jieshu == 'yes'里面添加了发送方式,因为要把结束前的数据发送过去。而且可以获得客户端的IP地址

效果如图

小结

udp虽然比较容易操作但是它的丢包问题让它有了上限,在比较重要的软件传输中尽量用tcp协议