简介
建一个基于 udp 的网络程序流程很简单,具体步骤如下:
- 创建客户端套接字
- 发送/接收数据
- 关闭套接字
注: 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(): udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
dest_ip = input('请输入对方的 ip: ') dest_port = int(input('请输入对方的 port :'))
print('请输入数据: ', end='') udp_socket.bind(('',7798)) while True: send_data = input() if send_data == 'exit': break ip_port = ('127.0.0.1',8080) udp_socket.sendto(send_data.encode('gbk'), ip_port) 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(): udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
local_addr = ('', 7788) udp_socket.bind(local_addr)
while True: recv_data = udp_socket.recvfrom(1024) recv_msg = recv_data[0] send_addr = recv_data[1] msg_decode = recv_msg.decode("gbk") if msg_decode == 'exit': break print("%s:%s" % (str(send_addr), msg_decode))
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 在数据没有到来的时候,会堵塞在那里)