Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯。
Python 中,我们用 socket() 函数来创建套接字,语法格式如下:
socket.socket([family[, type[, proto]]])
SOCK_STREAM(UDP方式)
或SOCK_DGRAM(TCP方式)
UDP(User Datagram Protocol,用户数据报协议)是一种无连接的协议,用于在IP主机和应用程序之间发送数据报。与TCP(Transmission Control Protocol,传输控制协议)不同,UDP不提供数据报的排序、重传或确认机制,因此被称为不可靠的协议。
1、向指定主机和端口发送消息
2、指定接收消息的端口并接收消息、
3、使用多线程方法一直接收消息
1、创建UDP套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
2、绑定接收端口
udp_socket.bind(("", 8888))
3、发送消息
因为计算机间的通信是二进制的,需要使用encode()方法将发送的数据转为二进制
udp_socket.sendto(send_str.encode(), (ip_str, port))
4、接收消息
recvfrom的返回值是一个元组,接收到的消息分为两部分,一部分是消息内容,一部分是发送方的ip和端口。同样的接收到的消息需要使用decode()方法解码
data = udp_socket.recvfrom(1024)
import socket
import threading
"""UDP聊天器"""
def Socket_Sento(udp_socket):
ip_str = input("请输入对方的ip地址:")
port = int(input("请输入对方的端口号:"))
send_str = input("请输入要发送的内容:")
udp_socket.sendto(send_str.encode(), (ip_str, port))
def Socket_Recvfrom(udp_socket):
while True:
data = udp_socket.recvfrom(1024)
print("来自主机:%s:%d发来的消息:%s\n" % (data[1][0], data[1][1], data[0].decode("gbk")))
def main():
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_socket.bind(("", 8888))
t1 = threading.Thread(target=Socket_Recvfrom, args=(udp_socket,), daemon=True)
t1.start()
while True:
print("\n\n***************************")
print("****** 1、发送信息 *******")
print("****** 2、退出系统 *******")
print("***************************")
num = input("请选择功能序号\n")
if num == "1":
Socket_Sento(udp_socket)
elif num == "2":
break
else:
print("输入错误")
udp_socket.close()
if __name__ == "__main__":
main()
TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。
使用TCP时与UDP不同,需要先建立连接
tcp_client_socket.connect(("192.168.56.1",8080))
import socket
# 创建套接字
tcp_client_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 建立连接
tcp_client_socket.connect(("192.168.56.1",8080))
# 发送数据
tcp_client_socket.send("约吗".encode())
# 接收数据
print(tcp_client_socket.recv(1024).decode("gbk"))
tcp_client_socket.close()
当TCP作为服务端的时候需要设置地址重用、绑定端口、设置监听
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
tcp_server_socket.bind(("", 8080))
tcp_server_socket.listen(128)
import socket
import threading
"""多线程TCP服务框架"""
def recv_msg(new_socket, client_port):
while True:
recv_data = new_socket.recv(1024)
if recv_data:
print("来自[%s]发送的数据:%s" % (client_port, recv_data.decode("gbk")))
else:
print("客户端已断开连接")
break
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置地址重用
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 绑定端口
tcp_server_socket.bind(("", 8080))
# 设置监听
tcp_server_socket.listen(128)
# 循环实现多个客户端连接
while True:
new_socket, client_port = tcp_server_socket.accept()
print("与%s连接成功" % str(client_port))
recv_thread = threading.Thread(target=recv_msg, args=(new_socket, client_port), daemon=True)
recv_thread.start()
# tcp_server_socket.close()
浏览器的请求分为get请求和post请求
get请求的请求协议包含请求行、请求头、请求空行
post请求的请求协议包含请求行、请求头、请求空行、请求内容
import socket
# 创建套接字
tcp_client_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 建立连接
tcp_client_socket.connect(("127.0.0.1",8080))
# 拼接请求协议
# 请求行
request_line="GET / HTTP/1.1\r\n"
#请求头
request_header="Host:www.baidu.com\r\n"
#请求空行
requset_blank="\r\n"
request_data=request_line+request_header+requset_blank
#发送请求协议
tcp_client_socket.send(request_data.encode())
#接收服务器响应内容
respon_data=tcp_client_socket.recv(4096).decode()
html_data=respon_data[respon_data.find("\r\n\r\n")+4:]
print(html_data)
# 保存内容
with open("D:\\PycharmProjects\\TextProject\\Text_TCP_Web\\index.html","w") as file:
file.write(html_data)
#关闭连接
tcp_client_socket.close()
首先需要解码请求协议,将接收到的请求解码拆分得到要请求的内容
然后创建响应协议:响应行、响应头、响应空行、响应主体,最后拼接发送给请求端
import socket
def request_headler(new_client_socket, ip_port):
request_data = new_client_socket.recv(1024).decode()
# print(request_data)
# 接收客户端浏览器发送的请求
# 判断协议是否为空
if not request_data:
print("%s用户已下线" % str(ip_port))
new_client_socket.close()
return
# 根据客户端浏览器请求的资源路径,返回请求资源
# 把请求协议解码,得到请求报文的字符串
# 得到请求行
# 查找第一个\r\n出现得位置
# 使用切片获取请求行
requst_line = request_data[0:request_data.find("\r\n")]
# 按空格分割创建数组
requst_line_list = requst_line.split(" ")
# 获取到指定文件
file_path = requst_line_list[1]
# 如果没有指定访问的文件就返回默认首页
if file_path == "/":
file_path = "index.html"
print("[%s]用户请求了%s资源" % (str(ip_port), file_path))
# 拼接响应的报文
# 响应行
respon_line = "HTTP/1.1 200 OK\r\n"
# 响应头
respon_header = "Server:Python\r\n"
# 响应空行
respon_blank = "\r\n"
# 响应主体
# respon_body = "Hello Wolrd"
# 返回指定页面
try:
with open("..\\static\\" + file_path, "rb") as file:
respon_body = file.read()
except Exception as e:
respon_line = "HTTP/1.1 404 Not Found\r\r"
respon_body = "Error! (%s)" % e
respon_body = respon_body.encode()
# 发送响应报文
respon_data = (respon_line + respon_header + respon_blank).encode() + respon_body
new_client_socket.send(respon_data)
def main():
# 创建套接字
tcp_sderver_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口重用、
tcp_sderver_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 绑定端口
tcp_sderver_socket.bind(("", 8080))
# 设置监听,让套接字由主动变为被动接收
tcp_sderver_socket.listen(128)
# 接受客户端的请求 定义函数request_handler()
while True:
new_client_socket, ip_port = tcp_sderver_socket.accept()
print("新用户%s来了" % str(ip_port))
request_headler(new_client_socket, ip_port)
# 关闭操作
tcp_sderver_socket.close()
if __name__ == "__main__":
main()
import socket
clinent_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
clinent_socket.connect(("192.168.56.1",8080))
file_name=input("请输入要下载的文件名:")
clinent_socket.send(file_name.encode())
with open("C:\\Users\\Administrator\\Desktop\\copy\\"+file_name, "wb") as source_file:
while True:
file_data = clinent_socket.recv(1024)
if file_data:
source_file.write(file_data)
else:
break
clinent_socket.close()
import socket
server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_socket.bind(("",8080))
server_socket.listen(128)
while True:
new_server_socket,clinet_port=server_socket.accept()
print("客户端[%s]已连接"%str(clinet_port))
clinet_data=new_server_socket.recv(1024)
try:
with open("C:\\Users\\Administrator\\Desktop\\"+clinet_data.decode(),"rb") as server_file:
while True:
file_date=server_file.read(1024)
if file_date:
new_server_socket.send(file_date)
else:
print("文件传输完成")
break
except Exception as e:
print("文件%s传输失败"%clinet_data.decode())
new_server_socket.close()
server_socket.close()