python socket
客户端/服务器架构
即C/S架构,包括
1.硬件C/S架构(打印机)
2.软件C/S架构(web服务)
美好的愿望:
最常用的软件服务器是 Web 服务器。一台机器里放一些网页或 Web 应用程序,然后启动 服务。这样的服务器的任务就是接受客户的请求,把网页发给客户(如用户计算机上的浏览器),然 后等待下一个客户请求。这些服务启动后的目标就是“永远运行下去”。虽然它们不可能实现这样的 目标,但只要没有关机或硬件出错等外力干扰,它们就能运行非常长的一段时间。
生活中的C/S架构:
老男孩是S端,所有的学员是C端
饭店是S端,所有的食客是C端
互联网中处处是C/S架构(黄色网站是服务端,你的浏览器是客户端;腾讯作为服务端为你提供视频,你得下个腾讯视频客户端才能看狗日的视频)
C/S架构与socket的关系:
我们学习socket就是为了完成C/S架构的开发
模拟打电话
服务端
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机
phone.bind(('127.0.0.1',8000)) #绑定手机卡
phone.listen(5) #开机
print("------->")
conn,addr = phone.accept() #等电话
msg = conn.recv(1024) #收到消息
print("客户端发来的是",msg)
conn.send(msg.upper()) #发消息
conn.close()
phone.close()
客户端
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8000)) #拨通电话
phone.send("hellohgjgjgjk".encode("utf-8")) #发消息
data = phone.recv(1024)
print("收到服务端的是:",data)
phone.close()
服务端
# tcp服务端
from socket import *
ip_port = ("127.0.0.1",8080)
back_long = 5
buffer_size = 1024
tcp_sever = socket(AF_INET,SOCK_STREAM)
tcp_sever.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #解决重启服务端出现Address already in use
tcp_sever.bind(ip_port)
tcp_sever.listen(back_long)
while True: #外层循环用循环接收不同的链接
print("服务端开始运行了")
conn,addr = tcp_sever.accept()
print("双向链接是",conn)
print("客户端地址是",addr)
while True: #内层循环用来基于一次链接循环通信
try:
data = conn.recv(buffer_size)
if not data:break
print('客户端发来的消息是 ',data.decode("utf8"))
conn.send(data.upper())
except Exception:
break
conn.close()
tcp_sever.close()
客户端
# tcp客户端
from socket import *
ip_port = ("127.0.0.1", 8080)
buffer_size = 1024
tcp_client = socket(AF_INET, SOCK_STREAM)
tcp_client.connect(ip_port)
while True:
msg = input(">>>").strip()
if not msg:continue
tcp_client.send(msg.encode("utf8"))
print("客户端已经发消息了")
data = tcp_client.recv(buffer_size)
print("收到服务端发的消息是 ",data.decode("utf8"))
tcp_client.close()
服务端解决粘包
#服务端(自定制报头)
from socket import *
import subprocess
import struct
ip_port=('127.0.0.1',8080)
back_log=5
buffer_size=1024
tcp_server=socket(AF_INET,SOCK_STREAM)
tcp_server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #解决重启服务端出现Address already in use
tcp_server.bind(ip_port)
tcp_server.listen(back_log)
while True:
conn,addr=tcp_server.accept()
print('新的客户端链接',addr)
while True:
#收
try: #客户端断开,会捕捉到异常
cmd=conn.recv(buffer_size)
if not cmd:break
print('收到客户端的命令',cmd)
#执行命令,得到命令的运行结果cmd_res
res=subprocess.Popen(cmd.decode('utf-8'),shell=True,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
stdin=subprocess.PIPE)
err=res.stderr.read()
if err:
cmd_res=err
else:
cmd_res=res.stdout.read()
#发
if not cmd_res:
cmd_res='执行成功'.encode('utf8')
length=len(cmd_res)
data_length=struct.pack('i',length)
conn.send(data_length)
conn.send(cmd_res)
except Exception as e:
print(e)
break
客户端解决粘包
#客户端(自定制报头)
from socket import *
import struct
from functools import partial
ip_port=('127.0.0.1',8080)
buffer_size=1024
tcp_client=socket(AF_INET,SOCK_STREAM)
tcp_client.connect(ip_port)
while True:
cmd=input('>>: ').strip()
if not cmd:continue
if cmd == 'quit':break
tcp_client.send(cmd.encode('utf-8'))
#解决粘包
length_data=tcp_client.recv(4)
length=struct.unpack('i',length_data)[0] #服务端发回来的数据长度
recv_size=0
recv_msg=b''
while recv_size < length:
recv_msg += tcp_client.recv(buffer_size)
recv_size=len(recv_msg) #1024
print('命令的执行结果是 ',recv_msg.decode('utf8'))
tcp_client.close()
服务端 传文件
from socket import *
ip_port = ("127.0.0.1",8182)
back_long = 5
buffer_size = 1024
s = socket(AF_INET,SOCK_STREAM)
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind(ip_port)
s.listen(back_long)
conn,addr = s.accept()
filesize = conn.recv(buffer_size)
filesize = int(filesize)
p_size = 0
p = b""
while p_size < filesize:
p += conn.recv(buffer_size)
p_size = len(p)
with open("b.jpg","wb") as f:
f.write(p)
conn.close()
s.close()
客户端 传文件
from socket import *
import os
ip_port = ("127.0.0.1",8182)
buffer_size = 1024
c = socket(AF_INET,SOCK_STREAM)
c.connect(ip_port)
p_size = os.stat("a.jpg").st_size
c.send(str(p_size).encode("utf8"))
with open("a.jpg","rb") as f:
for i in f:
# print(i)
c.send(i)
c.close()
服务端socketserver(解决tcp多用户交流)
import socketserver
ip_port = ("127.0.0.1",8081)
buffer_size = 1024
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
print("conn is: ",self.request) #conn
print("addr is:",self.client_address) #addr
while True: #通信循环
try:
data = self.request.recv(buffer_size)
if not data:continue
print("客户端发来的消息是 ",data.decode("utf8"),self.client_address)
self.request.send(data.upper())
except Exception:
break
if __name__ == "__main__":
s = socketserver.ThreadingTCPServer(ip_port,MyServer)
s.serve_forever() #链接循环
客户端socketserver(解决tcp多用户交流)
from socket import *
ip_port = ("127.0.0.1",8081)
buffer_size = 1024
c = socket(AF_INET,SOCK_STREAM)
c.connect(ip_port)
while True:
msg = input(">>>:")
c.send(msg.encode("utf8"))
data = c.recv(buffer_size)
print("服务发来是消息是 ",data.decode())
c.close()
udp服务端
from socket import *
ip_port = ("127.0.0.1",8080)
buffer_size = 1024
udp_sever = socket(AF_INET,SOCK_DGRAM)
udp_sever.bind(ip_port)
while True:
data,addr = udp_sever.recvfrom(buffer_size)
print("客户端发来的是 ",data.decode("utf8"))
print("发消息来客户端的地址和端口是 ",addr)
udp_sever.sendto(data.upper(),addr)
udp客户端
from socket import *
ip_port = ("127.0.0.1",8080)
buffer_size = 1024
udp_client = socket(AF_INET,SOCK_DGRAM)
while True:
msg = input(">>>").strip()
udp_client.sendto(msg.encode("utf8"),ip_port)
data,addr = udp_client.recvfrom(buffer_size)
print("服务端发回的消息是 ",data.decode("utf8"))
udp服务端1
from socket import *
import time
ip_port = ("127.0.0.1",8080)
buffer_size = 1024
udp_sever = socket(AF_INET,SOCK_DGRAM)
udp_sever.bind(ip_port)
while True:
data,addr = udp_sever.recvfrom(buffer_size)
if not data:
fmt = "%Y-%m-%d %X"
else:
fmt = data.decode("utf8")
back_time = time.strftime(fmt)
print(back_time)
udp_sever.sendto(back_time.encode("utf8"),addr)
udp客户端1
from socket import *
ip_port = ("127.0.0.1",8080)
buffer_size = 1024
udp_client = socket(AF_INET,SOCK_DGRAM)
while True:
msg = input(">>>").strip()
udp_client.sendto(msg.encode("utf8"),ip_port)
data,addr = udp_client.recvfrom(buffer_size)
print("服务端发回的消息是 ",data.decode("utf8"))
浙公网安备 33010602011771号