概述
目的
在学习Socket编程时,个人认为回射服务器的编写有利于直观体验整个信息传输的过程。并且相较于C++,Python在编写回射服务器时更加简单,所以后续在充分掌握本项目的基础上,会补充**C++**的回射服务器。
准备工作
- 在该项目中,将体会到不同IP主机之间的交互关系,所以需要一个虚拟机,并且设置虚拟机连接为桥接,使得与本机的IP地址不同。由于后续将把客户端程序运行在本机,将回射服务器即服务器端运行在虚拟机上,所以会将两者以客户端和服务器代称。
- 这里用到的是Python3,想要在Python2上实现的朋友,请更改
input()
函数成raw_input()
函数,并做极少的修改,这里不在赘述。
目标效果
客户端将一串信息发送到服务器,服务器将收到的信息原封不动的回传至客户端指定端口。整个过程没有牵扯到多线程,是最基本的回射服务器类型。
相关函数介绍
包的导入
from socket import *
UDP套接字的创建
以下函数接收两个参数来创建套接字,第一个参数表示IPV4,第二个参数表示UDP协议。
mySocket = socket(AF_INET, SOCK_DGRAM)
地址及端口设置
IP地址在前,端口号在后,元组形式。
address = ('192.168.0.1', 8888)
套接字绑定端口
若要从某一端口接收数据,则需要提前将套接字与该端口绑定。
mySocket.bind(address)
接收数据
利用
recvfrom
函数接收数据,需要设定读取长度,这里设为1024
。程序执行到这条语句时会阻塞,当从该端口读到数据时,程序会继续执行。
data = mySocket.recvfrom(1042)
发送数据
利用
sendto
函数发送数据,该函数接收两个参数,第一个参数为发送内容,第二个参数为元组形式的目标地址信息,格式与上述address
变量相同。
mySocket.sendto(data, address)
模块介绍及代码
注意
这里将用到三个模块,第一个模块为客户端,第二个为服务器,第三个为方便显示回传信息的显示模块。其中,模块1与3分别运行在本机的两个终端窗口上,模块2运行在虚拟机上。
啰嗦一句,程序运行命令为:
python3 (文件名).py
。三个模块请分别保存为三个不同的py
文件。
客户端代码
第
8
行的IP需换成运行服务器程序的虚拟机IP地址,并且目标端口号应与后续服务器接收端口对应。
# UDP客户端
from socket import *
# 创建套接字
udpSocket = socket(AF_INET, SOCK_DGRAM)
# 设置发送地址、端口
aimAddress = ('192.168.43.175', 8090)
while True:
# 后续函数接收bytes类型的串,此处需要转码
data = input("键入需要传送的数据\n").encode()
# 发送
udpSocket.sendto(data, aimAddress)
udpSocket.close()
回射服务器代码
第
11
行的回射端口号,应与后序的客户端接收程序所绑定的端口号相同。
# 简单的UDP回射服务器
from socket import *
# 创建套接字
udpSocket = socket(AF_INET, SOCK_DGRAM)
# 绑定本地接收端口
localAddress = ('', 8090)
udpSocket.bind(localAddress)
# 定义回射端口
aimPort = 9000
while True:
# 接收
recvData = udpSocket.recvfrom(1024)
aimAddress = (recvData[1][0], aimPort)
# 转发
udpSocket.sendto(recvData[0], aimAddress)
# 打印log信息
print("Message passed --- {} : {}".format(recvData[0], aimAddress))
udpSocket.close()
接收显示模块代码
# 用来显示收到的数据
from socket import *
# 创建套接字
udpSocket = socket(AF_INET, SOCK_DGRAM)
# 绑定本地接收端口
bindAddress = ('', 9000)
udpSocket.bind(bindAddress)
while True:
# 接收
rec = udpSocket.recvfrom(1024)
# 打印接收内容
print("Data : {} | from : {}".format(rec[0].decode(), rec[1]))
udpSocket.close()