Python网络编程-----UDP协议

要进行网络间的通信,首先要唯一标识一个进程,利用前面提到的IP和端口号我们可以唯一的标识一个进程⽤这个标志与其它进程进⾏交互。这个就是网络编程,又称为socket(简称为套接字)编程。

1. socket对象的创建

socket(简称套接字)是进程间通信的⼀种⽅式,在Python中我们用socket模块来实现网络编程,在socket模块中一个socket函数可以创建socket对象。其中有两个参数,第一个参数可以选择AF_INET(用于Internet进程间通信)或AF_UNIX(用于同一台机器间进程的通信),实际工作中常用前者,因为前者也能实现同一台机器间进程的通信,第二个参数是套接字类型,可以是SOCK_STREAM(流式套接字,主要用于TCP协议)或SOCK_DGRAM(数据报套接字,主要用于UDP协议)

import socket
s = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)

2. UDP协议

UDP(User Datagram Protocol):用户数据播报协议,是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。UDP不提供可靠性,它只把应用程序传给IP层的数据发送出去,但不能保证他们能达到目的地。由于UDP在发送数据前不在客户与服务器间建立一个连接,且没有超时重发等级制,故而传输速度极快。

UDP是一种面向无连接的协议,每次数据播报都是一个独立的信息,包括完整的源地址和目的地址,它在网络上以任何可能的路径传往目的地,至于能否达到目的地以及内容的正确性不能保证。

UDP可以实现广播发送。UDP传输数据时有大小限制,每个传输的数据包必须限定在64KB之内。UDP适用于语音播报、视频会议系统、QQ消息文件的上传和下载、TFTP、SNMP等。

3. 实现UDP客户端的数据传输和接受

创建一个UDP客户端程序的流程如下:1.创建客户套接字 2.发送和接受数据 3.关闭套接字

1.不绑定IP和端口

UDP传输数据时以gbk编码传输,接受到的信息要进行解码

import socket
# 创建socket对象
ss = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
# 对方的IP和接收数据的端口组成的套接字 用来发送信息
address = ("192.168.14.30", 8080)
msg = input("输入发送的内容:")
# 发送信息
ss.sendto(msg.encode("gbk"), address)
# 接受对方发送过来的信息 限制传输的数据的大小 返回的是(msg, (ip, port))
# msg对方传输的数据 ip对方的ip port对方传输数据的端口
data = ss.recvfrom(1024)
print("接受来自于{} {}的信息:{}".format(data[1][0], data[1][1], msg.decode("gbk")))
# 关闭连接
ss.close()

2. 绑定IP和端口

如果仅仅是用于发送信息的话不用绑定端口,但想要接受信息必须绑定端口,

import socket
# 创建socket对象
ss = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
# ""指的是本机
ss.bind("", 8081)
# 对方的IP和接收数据的端口组成的套接字 用来发送信息
address = ("192.168.14.30", 8080)
msg = input("输入发送的内容:")
# 发送信息
ss.sendto(msg.encode("gbk"), address)
# 接受对方发送过来的信息 限制传输的数据的大小 返回的是(msg, (ip, port))
# msg对方传输的数据 ip对方的ip port对方传输数据的端口
data = ss.recvfrom(1024)
print("接受来自于{} {}的信息:{}".format(data[1][0], data[1][1], msg.decode("gbk")))
# 关闭连接
ss.close()

3. 向UDP协议的软件发送信息

发送信息的格式如下:版本:包编号:发送者姓名:发送者机器名:命令字:消息

这是个死循环,循环发送信息,很容易造成敌方软件死机,慎用。

import socket

s = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
address = ("192.168.14.4", 2425)

try:
    while True:
        # msg = input("请输入你要发送的信息:")
        data = "1:12323434:垃圾胖子:QIKU-20180502BU:32:{}".format("垃圾胖子就是垃圾")
        s.sendto(data.encode("gbk"), address)
except Exception as e:
    print("发送错误,错误信息是", e)
finally:
    s.close()

4.UDP广播

向当前网段的2425端口循环发送广播,这个没有实现成功,但程序运行不报错。

udp = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
udp.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
addr = ("<broadcast>", 2425)
while True:
    msg = input(">>>")
    udp.sendto(msg.encode("gbk"), addr)
i = 0
while i < 10:
    (buf, address) = udp.recvfrom(2048)
    print("接收到%s=====>%s" % (address, buf.decode("gbk")))
    i += 1
udp.close()
print("successful")

4 UDP多线程编程

from threading import Thread, Lock


def send_msg(ip="192.168.14.30", port=8888):
    import socket
    s = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
    tup = (ip, port)
    while True:
        # print(">>>", end="")
        con = input("")
        if con != "q":
            s.sendto(con.encode("gbk"), tup)
        else:
            break
    s.close()


def rec_msg(ip="192.168.14.30", port=8889):
    import socket
    ss = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
    # 绑定ip和端口用于接受信息
    ss.bind((ip, port))
    while True:
        # 限制每秒接受的每件的大小
        rec = ss.recvfrom(1024)
        msg = rec[0].decode("gbk")
        if msg != "q":

            print("\n{}>>>".format(rec[1][0]), msg)
        else:
            print(">>>", "通话结束")
            break
    ss.close()


# 用多线程实现发送消息和接受消息
if __name__ == '__main__':
    t1 = Thread(target=send_msg, args=["192.168.14.30", 8889])
    t2 = Thread(target=rec_msg, args=["192.168.14.30", 8890])
    t1.start()
    t2.start()

5.用协程实现UDP传输数据

def send_msg(ip="192.168.14.30", port=8888):
    import socket
    s = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
    tup = (ip, port)
    while True:
        print(">>>", end="")
        con = input("")
        if con != "q":
            s.sendto(con.encode("gbk"), tup)
            yield 0
        else:
            break
    s.close()


def rec_msg(ip="192.168.14.30", port=8889):
    import socket
    ss = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
    # 绑定ip和端口用于接受信息
    ss.bind((ip, port))
    while True:
        # 限制每秒接受的每件的大小
        rec = ss.recvfrom(1024)
        # rec=(b'\xbb\xd8\xd2\xe4\xd7\xdc\xcf\xeb\xbf\xde\xa3\xac\xd2\xbb\xb8\xf6\xc8\
        # xcb\xb5\xc4\xd0\xd2\xb8\xa3\r\n', ('192.168.14.30', 8888))
        # print(rec)
        msg = rec[0].decode("gbk")

        if msg != "q":
            print("\n{}>>>".format(rec[1][0]), msg)
            yield 0
        else:
            print(">>>", "通话结束")
            break

    ss.close()


if __name__ == '__main__':
    t1 = send_msg()
    t2 = rec_msg()
    while True:
        next(t1)
        next(t2)
用协程实现UDP传输数据时,是双方轮流发送信息交流,若轮到一方发送信息,但它不发送信息,那么另一方不能发送信息。在用进程实现UDP数据传输时,由于进程间不支持input语句无法实现信息的输入,所以实现UDP传输数据用多线程最好。





猜你喜欢

转载自blog.csdn.net/qwerLoL123456/article/details/81037403