简介

建一个基于 udp 的网络程序流程很简单,具体步骤如下:

  1. 创建客户端套接字
  2. 发送/接收数据
  3. 关闭套接字

注: udp 对客户端与服务端的区分并不大,一个程序可以既作服务端,又作客户端,而且收发使用相同的函数方法。

UDP 通信模型

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import socket

def main():
#1. create socket
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

#手动输入对方的 ip 和端口
dest_ip = input('请输入对方的 ip: ')
dest_port = int(input('请输入对方的 port :')) # 注:这里要是输入了字母等非数字,会报错.可以使用try捕获.

print('请输入数据: ', end='')
# 绑定一个端口
udp_socket.bind(('',7798))
while True:
# get message from keyboard
send_data = input()
#如果输入的是 exit, 那么就退出
if send_data == 'exit':
break
#2. use socket to send and receive data
# ip_socket.sendto('hehe', 对方的ip以及端口)
ip_port = ('127.0.0.1',8080)
#udp_socket.sendto(b'Hello World',ip_port)
udp_socket.sendto(send_data.encode('gbk'), ip_port)
# 3. close socket
udp_socket.close()

if __name__ == "__main__":
main()

print 函数默认会打印回车换行,如果不想这样,可以将 end 参数赋值为空字符串。

编码转换:

<class 'bytes'> 与字符串之间的转换:字节->字符串(解码,使用 decode),字符串->字节(编码,使用 encode),具体编解码使用的字符串与操作系统默认字符集有关,其中:Windows 默认字符集为 gbk, Mac 与 Linux 可以使用 utf-8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> type(b'2')
<class 'bytes'>
>>> str = b'hello'
>>> str
b'hello'
>>> string = str.decode()
>>> string
'hello'
>>> type(string)
<class 'str'>
>>> str_b = string.encode('gbk')
>>> str_b
b'hello'
>>> type(str_b)
<class 'bytes'>

服务端

如果只需要发送消息,那只需要随机端口即可. 但如果需要接收消息的话(即:服务端),需要绑定固定的端口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import socket

def main():
# 1. 创建套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 2. 绑定本地信息
local_addr = ('', 7788)
udp_socket.bind(local_addr)

while True:
# 3. 接收数据
recv_data = udp_socket.recvfrom(1024)
# recv_data 这个变量中存储的是一个元组(接受到的数据,(发送方的 ip, port))
recv_msg = recv_data[0] # 存储接收到的数据
send_addr = recv_data[1] # 存储发送方的地址信息.
msg_decode = recv_msg.decode("gbk")
if msg_decode == 'exit':
break
# 4. 打印接收到的数据
#print(recv_data)
print("%s:%s" % (str(send_addr), msg_decode))

# 5. 关闭套接字
udp_socket.close()

if __name__ == '__main__':
main()

bind 函数绑定本地 ip 以及端口, 如果一个网络程序不绑定,则系统会随机分配.

bind 函数的参数也是一个 ip port 元组,其中本地 ip 的话,就直接写一个空的字符串即可. 表示本地的任意一个 ip. 绑定信息的时候必须绑定自己电脑的 ip 以及 port,绑定别的电脑的不行.

recv_data 这个变量中存储的是一个元组(接受到的数据,(发送方的 ip, port))。

一般我们接收到数据后,将 recv_data[0] 使用 decode 从 bytes 解码为 string, 将 recv_data[1] 直接强制转换为字符串打印出来。

当对方发送数据过来时,操作系统先使用缓冲区存储起来,应用程序 recvfrom 取数据的时候,才会从缓冲区取出数据。这样就容易造成缓冲区溢出。所以一般我们的应用程序如果要接收数据,一般都使用 while True 接收(recvfrom 在数据没有到来的时候,会堵塞在那里)