16-网络通信
网络编程
- 同一个网络中不同的机器之间的通信,涉及到网络编程,有两方,一方叫做客户端(client),一方叫做服务器(server)(B/S,C/S)
- IP地址
- 互联网协议地址【Internet Protocol Address】,是联网设备和互联网之间的唯一标识,在同一个网段中,ip地址是唯一的
- IP地址是一个32位的数字,255.255.255.255 # 被分割为4个八位二进制数,255转换为二进制11111111,八位
- IPV4:分为四段
- IPV6:分为六段
- 端口
- 数据的发送和接收都需要通过端口,端口号用于唯一标识通信实体上进行网络通信的程序
- 同一台机器上的不同的应用程序不能占用同一个端口,端口的范围:0~65535
- 常用端口
- mysql: 3306
- oracle:1521
- tomcat:8080
- qq:4000
- 0-1024端口号不能用,常用的服务占用了
- 网络协议
- http: 被动式协议
- tcp
- udp
- tcp/ip:互联网协议,协议簇
- 网络编程核心
- ip地址+端口号
- 根据ip地址找到计算机,然后根据端口号找到进程
- socket
- socket:实现网络编程的方式, 套接字
tcp
-
特点
- 面向连接、可靠(超时重发)、慢
- tcp是长连接,可以让客户端和服务器端一直连接着,TCP常用于即时通信IM,如:QQ,微信,游戏
- 类似于生活中的打电话
-
上网:http使用的tcp连接
-
tcp连接过程
- 3次握手
- 3次握手
-
tcp断开过程
- 4次挥手
- 4次挥手
-
tcp通讯
-
服务器Server
-
导入socket,创建socket对象,绑定(bind)IP地址和端口,设置监听数,等待客户端连接(accept),连接成功后进行收发(recv,send)数据,关闭连接
-
# TCP通讯 服务端 import socket # 1.创建一个socket对象(服务端) # AF_INIT: IPV4 # AF_INET6:IPV6 # SOCK_STREAM:表示TCP # SOCK_DGRAM:表示UDP协议 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 2.绑定IP和PORT(端口) server_socket.bind(('127.0.0.1', 8888)) # 3.设置监听数(客户端连接数) server_socket.listen(5) # 4.等待客户端来连接我 print('服务器已启动,等待客户端连接……') client, addr = server_socket.accept() # 会让程序暂停 # (<socket.socket fd=480, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('10.36.139.18', 8888), raddr=('10.36.139.18', 54708)>, ('10.36.139.18', 54708)) # print(client) # print(addr) print('有客户端连接成功了') # 5.连接成功后,就可以开始收发数据了 while True: # 接收数据,阻塞程序(让程序暂停) data = client.recv(1024) print('客户端说:', data.decode()) # 发送数据给客户端 data2 = input('输入发送给客户端的数据') client.send(data2.encode()) # client.send('今晚吃鸡吗'.encode()) # 6.关闭连接 # server_socket.close()
-
# 多个客户端同时通信-多线程版 # 服务器 from threading import Thread import socket def message(sock): while True: recv_data = sock.recv(1024) if not recv_data: break print(recv_data.decode()) data = 'hello %s' % recv_data.decode() sock.send(data.encode()) sock.close() server = socket.socket() server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind(('127.0.0.1', 8888)) server.listen(5) while True: sock, address = server.accept() t = Thread(target=message, args=(sock, )) t.start()
-
# 多个客户端同时通信-协程版 # 服务端 from gevent import monkey monkey.patch_all() import gevent import socket def message(sock): while True: recv_data = sock.recv(1024) if not recv_data: break print(recv_data.decode()) data = 'hello %s' % recv_data.decode() sock.send(data.encode()) sock.close() server = socket.socket() server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind(('127.0.0.1', 8888)) server.listen(5) while True: sock, address = server.accept() g = gevent.spawn(message, sock) g.start()
-
# 单进程单线程非阻塞版 import socket import time server = socket.socket() server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind(('127.0.0.1', 8888)) server.listen(5) server.setblocking(False) sock_list = [] while True: try: sock, address = server.accept() # print('已链接') except: pass # print('没有链接') # time.sleep(1) else: sock_list.append(sock) for sock in sock_list: try: recv_data = sock.recv(1024) print(recv_data) except: pass # print('没有数据') else: if not recv_data: sock.close() sock_list.remove(sock) else: send_data = 'hello %s' % recv_data.decode() sock.send(send_data.encode())
-
-
客户端Client
-
导入socket,创建socket对象,主动连接服务器端(connect),收发数据
-
# TCP通讯 客户端 import socket # 1.创建socket对象(客户端) client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 2.主动连接服务器端 client_socket.connect(('127.0.0.1', 8888)) # 3.发送或接收服务器数据 while True: # 发送给服务器 data = input('输入发送给给服务器的数据:') client_socket.send(data.encode()) # 接收服务器数据 data2 = client_socket.recv(1024) print('服务器:', data2.decode())
-
-
udp
-
特点
- 不安全的,无连接,效率高速度快,对数据的大小是有限制的,每个被传输的数据包的大小不超过64k
- 类似于生活中的写信
-
udp通讯
-
服务器Server
-
导入socket包,创建socket对象,绑定IP和端口,收发(recvfrom,sendto)数据
-
# UDP 通讯 服务端 import socket # 1.创建UDP的socket对象 # SOCK_DGRAM:表示UDP server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 2.绑定IP和port server_socket.bind(('10.36.139.18', 6666)) # 3.收发数据 while True: # 接收数据,会阻塞程序 data, addr = server_socket.recvfrom(1024) print(f'客户端{addr}说:', data.decode()) # 发送 server_socket.sendto('今晚吃鸡'.encode(), addr)
-
-
客户端Client
-
导入socket包,创建socket对象,收发数据
-
# UDP 通讯 客户端 import socket # 1.创建UDP的socket对象 client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 2.收发数据 while True: # 发送数据 data = input('客户端说:') client_socket.sendto(data.encode(), ('10.36.139.197', 5677)) # 接收数据 data2, addr = client_socket.recvfrom(1024) print('服务器说:', data2.decode())
-
-
模拟飞秋
-
import socket client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 发送飞秋消息 # 1:表示版本 # 1:自定义的一个包名 # 王宝强:用户名 # baoqiang:主机名 # 32:表示发送数据 # 'hello你中毒了':发送的内容 msg = '1:1:宝强:baoqiang:32:hello你中毒了' client_socket.sendto(msg.encode('gbk'), ('10.36.139.18', 2425))
-
-
发送邮件
-
import smtplib
-
from email.mime.text import MIMEText
-
服务器IP及端口
-
收发对象及授权码
-
# 163邮箱 import smtplib from email.mime.text import MIMEText # 邮件 # 163的邮箱服务器:smtp.163.com # smtp端口:25 # 邮箱账号niejeff@163.com # 授权码:123456abcde smtp_server = 'smtp.163.com' smtp_port = 25 from_email = 'niejeff@163.com' email_code = '123456abcde' # 这里不是邮箱的密码,而是授权码 to_email = ['593825767@qq.com'] # 可以写多个 # 创建邮件 msg = MIMEText('今晚来我家吃鸡') # 邮件内容 msg['Subject'] = '大吉大利' # 标题 msg['From'] = from_email msg['To'] = '593825767@qq.com' # 不能是列表 # 创建邮箱对象,来发送邮件 smtp = smtplib.SMTP(smtp_server, smtp_port) # 连接163邮箱服务器 smtp.login(from_email, email_code) # 登陆163邮箱 smtp.sendmail(from_email, to_email, msg.as_string()) # 关闭 smtp.close()
-
# QQ邮箱 import smtplib from email.mime.text import MIMEText smtp_server = 'smtp.qq.com' smtp_port = 587 from_email = '593825@qq.com' email_code = 'xnsihfyjhktnbdba' to_email = '593825@qq.com' # 创建邮件 msg = MIMEText('学会了吗?') msg['Subject'] = 'Python邮件' msg['From'] = from_email msg['To'] = to_email # 创建邮箱对象,发送邮件 smtp = smtplib.SMTP(smtp_server, smtp_port) # 连接QQ邮箱 smtp.login(from_email, email_code) # 登陆qq邮箱 smtp.sendmail(from_email, to_email, msg.as_string()) # 发送邮件 smtp.close()
-
发送短信
-
# 云之讯 import requests import random def send_sms(phone, vcode): ''' :param phone: 手机号 :param vcode: 验证码 ''' # 发送短信 # 云之讯的短信接口 url = 'https://open.ucpaas.com/ol/sms/sendsms' data = { "sid":"d84885ebbb2474f9a036346653dab29c", "token":"657e97e7906839b34acd71a70f86e938", "appid":"786ea1a774054eaeb1201c3a744b92ba", "templateid":"556407", "param":vcode, "mobile":phone, } res = requests.post(url, json=data) return res.text def generate_vcode(): ''' 生成随机6位验证码 ''' vcode = '' for _ in range(6): vcode += str(random.randint(0, 9)) return vcode if __name__ == '__main__': vcode = generate_vcode() print('vcode:', vcode) res = send_sms('18840864123', vcode) print(res)