一、何为socket编程
应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要通过同一个TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了称为套接字 (Socket)的接口,区分不同应用程序进程间的网络通信和连接。
生成套接字的两个参数,一个是选择IP协议,另一个是选择UDP或者是TCP.
代码语言:javascript复制# 创建一个udp套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#创建一个套接字, family=AF_INET type=NI_DGRAM
# 创建一个TCP套接字
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
这里family的意思是选择哪种协议,AF_INET代表的是IPv4,SOCK_DGRAM创建的是UDP协议。
二、UDP套接字的收发流程
1.创建一个UDP套接字
2.套接字收发数据
3.关闭套接字
例子的代码如下:(需要打开网路调试助手进行辅助)
代码语言:javascript复制def main():
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#创建一个套接字, family=2 即family=AF_INET type=16 即type=NI_DGRAM
send_content = 666
# 发送数据的内容
# send_content = send_content.encode('gbk')
host_addr = ("169.254.190.219", 8080)
udp_socket.sendto(send_content, host_addr)
udp_socket.close()
# 套接字发送数据
def main():
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
desc_addr = ("169.254.190.219", 8080)
udp_socket.bind(("", 9999))
while True:
send_content = input("请输入要发送的数据:")
if send_content == "q":
break
send_content=send_content.encode('gbk')
udp_socket.sendto(send_content, desc_addr)
# 套接字接收数据
def main():
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
rec_addr = ("169.254.190.219", 9999)
udp_socket.bind(rec_addr)
rec_data = udp_socket.recvfrom(1024)
print(rec_data)
rec_content = rec_data[0].decode('gbk')
print("接收的内容为:{}n发送地址为:{} 端口为:{} ".format(rec_content,rec_data[1][0],rec_data[1][1]))
udp_socket.close()
# 套接字无限循环接收消息
def main():
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
rec_addr = ("169.254.190.219", 9999)
udp_socket.bind(rec_addr)
while True:
rec_data = udp_socket.recvfrom(1024)
rec_content = rec_data[0].decode('gbk')
if rec_content == "再见":
break
print("接收的内容为:{}n发送地址为:{} 端口为:{} ".format(rec_content,rec_data[1][0],rec_data[1][1]))
if __name__ == "__main__":
main()
在这里有几个注意事项:
1.在发送中文的时候,我们应该使用encode(“gbk”)进行编码,而不使用utf-8的原因是Windows默认的字体编码是GBK模式。
2.在接收中文的时候也应该使用decode进行解码。
3.发送的数据如果没有编码的话,默认只能发送字节类型的数据。
三、如何使用UDP套接字又接收又发送消息呢?
如果我们想要使用udp套接字又发送消息又接收消息的话,我们可以定义一个发送消息的函数和一个接收消息的函数,其余部分可以在主函数当中完成。
首先,我们需要绑定一个ip地址发送数据,其次,我们还需要一个IP地址来接收发送的数据。当然,聊天器的版本并不高,返回的值也是我们所输入的值,当然,如果箱套聊天器变得更加有趣,我们可以对其进行进行升级。这个时候其实只要加入一些判断语句就可以实现哦。比如,我们可以在输入全部都是英文的时候发送“乖乖,你发的都是些什么内容呀,我的智商太低完全看不懂哦”
代码语言:javascript复制import socket
'''
这是一个自己跟自己聊天的聊天器
第一版:
1.要绑定一个ip地址发送数据
2.要绑定一个ip地址来接收发送的数据
'''
def sendaddr(udp_socket):
send_addr = ("169.254.190.219",9999)
# udp_socket.bind(send_addr)
send_content = input("请输入要输入的内容:")
udp_socket.sendto(send_content.encode('gbk'),send_addr)
def recaddr(udp_socket):
rec_data = udp_socket.recvfrom(1024)
rec_content = rec_data[0].decode('gbk')
if rec_content == "exit":
exit()
print("接收的内容为:{}n发送地址为:{} 端口为:{} ".format(rec_content,rec_data[1][0],rec_data[1][1]))
def main():
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_socket.bind(("169.254.190.219", 9999))
while True:
sendaddr(udp_socket)
recaddr(udp_socket)
udp_socket.close()
if __name__ == "__main__":
main()
四、TCP套接字的创建流程
创建一个客户端的流程
1.创建一个套接字
2.连接服务器
3.发送或者是接收数据
4.关闭套接字
创建tcp客户端套接字的代码:
代码语言:javascript复制import socket
'''
创建TCP客户端的步骤:
1 创建套接字
2 连接服务端
3 接收或者是发送数据
4 关闭套接字
'''
# def main():
# tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# server_addr = ("169.254.190.219",8080)
#
# # 连接服务器
# tcp_client.connect_ex(server_addr)
#
# # 发送数据
# send_content = "haha"
# tcp_client.send(send_content.encode("gbk"))
#
# # 接收数据
# recv_data = tcp_client.recv(1024)
# print(recv_data.decode("gbk"))
# # 关闭套接字
# tcp_client.close()
#
# if __name__ == "__main__":
# main()
五、创建服务端的流程
1、创建一个套接字
2.绑定地址和端口
3.将主动改为被动
4.等待客户连接,创建出一个新的套接字
5.关闭套接字
代码如下:
代码语言:javascript复制'''
创建TCP服务端:
1 创建套接字
2 绑定地址
3 主动变被动
4 等待客户端连接
5 发送或接收数据
6 关闭套接字
'''# def main():
# # 创建套接字
# tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#
# # 绑定地址
# server_addr = ("169.254.190.219",8080)
# tcp_server.bind(server_addr)
#
# # 主动变被动
# tcp_server.listen(128)
#
# # 等待客户连接
# new_client_server, client_addr = tcp_server.accept()
# print(client_addr)
#
# # 接收数据
# recv_data = new_client_server.recv(1024)
# print(recv_data.decode('gbk'))
# #
# # 关闭套接字
# new_client_server.close()
# tcp_server.close()
# if __name__ == "__main__":
# main()
六、如何让一个服务端为多个客户服务
在日程生活中,我们不可能只为单一的客户服务,有可能有多个人同时排队服务。那这种情况下要怎么办呢?
简单的逻辑:
我们要循环主动变被动的过程,每一个客户都会生成一个新的套接字。
代码如下:
代码语言:javascript复制def main():
# 创建套接字
tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定地址和端口
server_addr = ("169.254.190.219", 8080)
tcp_server.bind(server_addr)
# 实现为多个客户端服务
while True:
# 变主动为被动
tcp_server.listen(128)
new_client_server, client_addr = tcp_server.accept()
# 为一个客户端多次服务
while True:
recv_data = new_client_server.recv(1024)
if recv_data.decode('gbk'):
print(recv_data.decode("gbk"))
new_client_server.send("消息已经收到".encode('gbk'))
else:
break
new_client_server.close()
tcp_server.close()
if __name__ == "__main__":
main()
七、使用TCP套接字模拟文件下载器
客户端
如果要使用套接字来模拟文件下载器的话,那么我们客户端大致主要完成的工作:
1.创建套接字
2.连接服务器
3.发送要下载的文件名
4.接收返回的数据
5.保存从服务器接收的数据
6.关闭套接字
实现代码:
代码语言:javascript复制# @日期:2020-01-10
# @作者:清欢
import socket
'''文件下载器
1.创建一个套接字
2.连接服务器
3.发送要下载的文件名
4.接收服务端返回的数据
5.保存数据
6.关闭套接字
'''
def save_data(circle):
with open("cilcle_copy.py","w",encoding="utf-8") as f:
f.write(circle.decode())
def main():
# 创建套接字
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接服务器
server_addr = ("169.254.190.219", 8080)
tcp_client.connect(server_addr)
# 发送要下载的数据名
load_name = input("请输入要下载的文件名")
tcp_client.send(load_name.encode())
# 接收返回的数据
Circle = tcp_client.recv(1024)
save_data(Circle)
#
if __name__ == '__main__':
main()
服务端
如果要完成文件下载器,服务端需要做的工作的大致流程:
1.创建套接字
2.绑定地址和IP
3.化主动为被动,等待客户端连接
4.创建客户的新的套接字
5.接收客户端发过来的文件名
6.读取文件的内容并返回给客户端
7.关闭套接字
代码语言:javascript复制# 练习
# 清欢
import socket
'''
文件下载器的服务端:
1 创建套接字
2 绑定地址和端口
3 变主动为被动
4 等待接收客户端发过来的文件名
5 读取文件信息
6 将文件信息发送给客户端
7 关闭套接字
'''
def main():
# 创建套接字
tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定地址和端口
server_addr = ("169.254.190.219",8080)
tcp_server.bind(server_addr)
# 变主动为被动
tcp_server.listen(128)
# 等待客户连接
new_client_server, client_addr = tcp_server.accept()
# 接收顾客发过来的文件名
recv_content = new_client_server.recv(1024).decode()
# 读取文件内容
if recv_content:
with open(recv_content, 'rb') as f:
file_content = f.read()
new_client_server.send(file_content)
else:
print("输入为空")
new_client_server.close()
tcp_server.close()
if __name__ == '__main__':
main()
TCP与UDP的区别
1、TCP面向连接;UDP是无连接的,即发送数据之前不需要建立连接
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
3、UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
5、TCP对系统资源要求较多,UDP对系统资源要求较少。