用udp模拟客户端:
声明:其实udp并不强调服务器与客户端的关系,通常来说服务器需要绑定端口,而客户端不需要绑定端口,而是在使用时候操作系统随便的给一个。UDP通信属于帧传输,TCP则是流传输,在帧传输过程中对于消息的次序和到达情况没有需求,所以UDP属于不可靠传输,不需要确认和排序。这样在客户端和服务器的实现上就没有太大的差别了。
需要的工具:在网上下载一个 网络调试助手
主要是用来模拟客户端、服务器啥的。里面可以选择3中类型(udp tcp_server tcp_client)
我们先选择UDP
模拟客户端的代码如下:
由于流程在代码注释在写的很详细、这里不再重复:
"""
主要是使用udp协议,连接模拟的服务器,发送消息、接收消息的过程
主要步骤:
1.创建套接字
2.提供服务器的ip地址、和端口号
3.发送数据、接受数据
4.关闭套接字
"""
import socket
class UdpClient(object):
# 初始化:需要提供一个元组包含服务器的ip地址和端口号
# 其中ip地址是字符串、端口号是数字
# 在初始化中需要创建一个udp套接字
def __init__(self):
print("第一步先创建一个套接字")
self.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
def set_ip_port(self):
# 其中ip地址是字符串、端口号是数字
print("")
print("----------------------------")
print("第二步,设置ip和port")
server_ip = input("请输入服务器的ip地址: ")
server_port = int(input("请输入服务器的port号: "))
self.add_info = (server_ip, server_port)
def send_mes(self):
print("")
print("----------------------------")
print("第三步,向服务器发送消息")
you_mes = input("请输入要发送给服务器的消息: ")
self.udp_socket.sendto(you_mes.encode("utf-8"), self.add_info)
def recv_mes(self):
print("")
print("----------------------------")
print("第四步,等待接收服务器发送的消息")
# recvfrom返回的是一个元组,第一个元素是对方发送的数据,第二个是一个小元组,里面是服务器的ip地址和端口号
recv_data = self.udp_socket.recvfrom(1024) # 1024表示字节大小,
# 打印接受到的消息
print(recv_data[0].decode("gbk")) # win是以GBK的编码方式编码的
print(recv_data[1])
def close_socket(self):
print("")
print("----------------------------")
print("第五步,关闭套接字")
self.udp_socket.close()
def main():
# 创建一个udp客户端,
my_udp_client = UdpClient()
# 调用set_ip_port方法设置要发送和接受消息的服务器的ip 和 port
my_udp_client.set_ip_port()
# 给服务器发送消息
my_udp_client.send_mes()
# 等待接受服务器的消息,如果服务器一直没有发送消息,程序会一直卡在这里,也就是堵塞在这里。
# 直到服务器发送消息过来,就会解堵塞,程序运行结束
my_udp_client.recv_mes()
# 关闭套接字
my_udp_client.close_socket()
if __name__ == "__main__":
main()
执行部分:
1.首先打开网络助手选择udp
2.点击连接下面的按钮(连接)
3.在linux终端下执行这个程序:
如下:
补充:如果我们在发送和接受消息部分、让循环,就可以实现一个简单的聊天器,不过由于recvfrom存在堵塞的情况,所以只能发一条,收一条。
但是我们使用多任务不管是进程、线程、和协程的方式,我们就能解决这个问题、让一个任务一直在跑发送消息、让一个任务一直在跑接收消息。
下面用udp绑定 ip和端口(假定我们写的程序作为服务器吧)
程序代码如下:跟上面的代码换汤不换药
需要注意的是在用网络助手的时候需要将绑定的端口号输入正确:
"""
主要是使用udp协议,假定创建一个服务器,而网络助手充当客户端
主要步骤:
1.创建套接字
2.绑定ip 和端口
3.发送数据、接受数据
4.关闭套接字
"""
import socket
class UdpServer(object):
# 在初始化中需要创建一个udp套接字
def __init__(self):
print("创建一个套接字")
self.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.ip_port = ("192.168.49.1", 8080)
def bind_ip_port(self):
print("")
print("----------------------------")
print("绑定ip和port")
self.udp_socket.bind(("", 8899))
def send_mes(self):
print("")
print("----------------------------")
print("向客户端发送消息")
you_mes = input("请输入要发送给客户端的消息: ")
# 我的win上的ip和地址为别如下:我们也可以等客户端发送消息过来捕捉到它的ip和端口然后
# 我们将ip port存储起来,在也行
self.udp_socket.sendto(you_mes.encode("gbk"), self.ip_port)
def recv_mes(self):
print("")
print("----------------------------")
print("等待接收客户端发送的消息")
# recvfrom返回的是一个元组,第一个元素是对方发送的数据,第二个是一个小元组,里面是服务器的ip地址和端口号
recv_data = self.udp_socket.recvfrom(1024) # 1024表示字节大小,
# 打印接受到的消息
print(recv_data[0].decode("gbk")) # win是以GBK的编码方式编码的
print(recv_data[1])
def close_socket(self):
print("")
print("----------------------------")
print("第五步,关闭套接字")
self.udp_socket.close()
def main():
# 创建一个udp服务器,
my_udp_srever = UdpServer()
# 调用set_ip_port方法设置要发送和接受消息的服务器的ip 和 port
my_udp_srever.bind_ip_port()
# 等待接受客户端的消息,如果客户端一直没有发送消息,程序会一直卡在这里,也就是堵塞在这里。
# 直到客户端发送消息过来,就会解堵塞,程序运行结束
my_udp_srever.recv_mes()
# 给客户端发送消息
my_udp_srever.send_mes()
# 关闭套接字
my_udp_srever.close_socket()
if __name__ == "__main__":
main()
TCP模拟客户端:
要注意的是:套接字在接收消息的时候只会接收字符串,不是一个元组了,不会有发送方(服务器)的ip port
因为你连接的时候已经知道了;
"""
程序的主要功能:
创建一个使用tcp协议,进行收发数据的客户端版本,让网络助手充当服务器
实现的主要步骤:
1.创建一个tcp的套接字
2.在连接服务器之前给定服务器的Ip和port号
3.connect服务器
4.将要发送的信息发送给服务器
5.接收服务器发送的消息
6.关闭套接字
"""
import socket
class TcpClient(object):
def __init__(self):
# 创建套接字
self.tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 初始化要连接的 ip port
self.server_ip = input("请输入要连接的服务器的ip: ")
self.server_port = int(input("请输入要连接的服务器的port: "))
def con_server(self):
# 使用conect连接服务器:函数接收的是元组
self.tcp_socket.connect((self.server_ip, self.server_port))
def send_mes(self):
# 向服务器发送消息
send_data = input("输入向服务器发送的消息:")
self.tcp_socket.send(send_data.encode("utf-8"))
def recv_mes(self):
# 接收服务器的消息,注意接收的不是元组,不会接收服务器的ip port 原因是:连接的时候已经知道了
recv_data = self.tcp_socket.recv(1024)
print("服务器发送的消息是: ",recv_data.decode("gbk"))
def close_socket(self):
self.tcp_socket.close()
def main():
# 创建一个tcpclient对象
tcp_client = TcpClient()
# 连接服务器
tcp_client.con_server()
# 发送消息
tcp_client.send_mes()
# 接收消息
tcp_client.recv_mes()
# 关闭套接字
tcp_client.close_socket()
if __name__ == "__main__":
main()
TCP模拟服务器:
"""
明确程序目标: 模拟使用tcp协议的 服务器端
步骤流程:
1.创建套接字
2.绑定端口 ip port
3.将主动设置为被动状态:监听套接字,这样就能被别人连接
4.等待客户端的连接:accept(),没有客户端连接就会一直堵塞、知道有客户端到来才会解堵塞
会产生一个专门为此时连接的客户端服务的套接字。这样监听套接字就能继续监听其他客户端的连接
5.发送和接收消息
"""
import socket
class TcpServer():
def __init__(self):
print("---------开始初始化---------")
self.judge = False # 主要是用来退出当前客户服务的循环
self.tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 对于服务器来说绑定一件很重要的事,所以我在初始化的时候就将其绑定,以免忘记
self.server_port = int(input("输入服务器的端口号: "))
self.tcp_socket.bind(("", self.server_port))
print("-----------结束初始化--------")
def listen_socket(self):
print("---设置为监听状态-----")
self.tcp_socket.listen(128) # 最大连接个数
print("-------设置完成------")
def accept_client(self):
# 等待客户端的连接,如果有链接、监听套接字就会产生一个新的套接字为这个客户端一对一服务
print("--------等待一个客户端的到来-----------")
self.client_socket, self.client_add = self.tcp_socket.accept()
print("--------一个新的客户端来了-------------")
def recv_mes(self):
print("-----------等待接收消息-------------")
# 接收客户端发送的消息
rec_data = self.client_socket.recv(1024)
# 如果客户端主动调用close()这里也会解堵塞。所以判断接收消息的长度
if rec_data:
print("接收到的客户端的消息是: ", rec_data.decode("gbk"))
else:
print("没有接收到消息,客户端调用了close")
self.client_socket.close()
self.judge = True
def send_mes(self):
print("-----------准备发送消息----------")
send_data = input("输入要发送的信息: ")
self.client_socket.send(send_data.encode("gbk"))
print("----------成功发送消息----------")
def close_socket_servet(self):
self.tcp_socket.close()
def main():
# 创建对象
tcp_server = TcpServer()
# 监听状态
tcp_server.listen_socket()
while True:
# 等待客户端的连接
flag = input("请输入是否需要等待客户端的到来:yes表示等待,其他不等待: ")
if flag == "yes":
tcp_server.accept_client()
while True:
# 做为服务器 当然是客户端发一个请求,我们回一个消息拉。
# 接收消息,没有接收到消息会关闭当前套接字
tcp_server.recv_mes()
# 发送消息
tcp_server.send_mes()
if tcp_server.judge:
break
#此时当前的套接字已经关闭,如果还需为这个客户端服务,只能重新连接
else:
# 如果不需要等待其他客户端的连接,就可以关闭监听套接字
tcp_server.tcp_socket.close()
print("程序结束")
break
if __name__ == "__main__":
main()