Socket
Socket(套接字),是进程间通信的方式。网络间进程间通信。
Socket是应用层的概念
在Socket中,当建立连接的方式,通过传输层有两种建立连接协议的方式:TCP协议、UDP协议
基操
首先是导入socket模块
import socket
然后通过socket类初始化socket对象
socket.socket(AddressFamily,type)
其中:
- AddressFamily:选择AF_INET即可
- type:套接字类型,可以为:
- SOCK_STREAM:流式套接字。主要指TCP协议
- SOCK_DGRAM:数据报套接字。主要指UDP协议
import socket # 创建一个流式套接字,用于TCP传输 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print('socket创建成功', s) s.close()
import socket # 创建一个数据报套接字,用于UDP传输 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) print('socket创建成功', s) s.close()
TCP:传输速度慢,但稳定。(打电话)
UDP:传输速度快,但不稳定(写信)
TCP
下面以TCP的服务端和客户端写一遍
服务端
while循环(服务器一般不能随便重启,保持循环),把accept()接收连接、recv()接收信息、send()发送信息的代码放到循环中
# TCP服务端 import socket # 创建一个流式套接字 用于TCP传输 server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 绑定端口 server_socket.bind(('',10086)) # 监听 参数表示可以接收客户端的个数 server_socket.listen(5) while 1: # 接收客户端的连接 # 服务端会在这里阻塞等待,直到客户端连接上 # 返回值1:连接的客户端的socket;返回值2:连接的客户端的信息 是一个元祖 包括地址和端口号 client_socket,client_info = server_socket.accept() # 接收客户端发送过来的数据 # recv()接收数据 注意与recvfrom()比较 recv_data = client_socket.recv(1024) print(recv_data) print(recv_data.decode('gbk')) # 给客户端返回一条信息 msg = 'get' client_socket.send(msg.encode('gbk')) # 关闭socket server_socket.close()
客户端
# TCP服务端 import socket # 创建一个流式套接字 用于TCP传输 client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 通过connect()函数连接服务端 # 参数是一个元组 里面包含服务端的地址和端口号 client_socket.connect(('192.168.30.35',10088)) # 给服务器发送一条消息 msg = '在吗' client_socket.send(msg.encode('gbk')) # 接收服务器返回等待消息 recv_data = client_socket.recv(1024) print(recv_data) print(recv_data.decode('gbk')) # 关闭socket client_socket.close()
UDP
- UDP是没有建立连接,所以每次发送信息的时候,都指定目的地,使用的函数是 sendto 、相应的接受函数是 recvfrom 。
- 比较TCP,是一开始就建立好连接,所以每次发送信息的时候,都无需再次指定目的地,使用的函数是 send 、相应接收函数是 recv 。
下面拿最UDP来写程序,我用网络调试助手设置其IP地址和端口号来检验代码:
UDP发送
import socket # 创建一个数据报套接字 用于UDP传输 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # sendto 通过udp发送信息 # 参数1 要发送的内容 # 参数2 发送的目的地 该参数是一个元组 里面有两个元素 # 1 目的地的IP地址 # 2 目的地的端口号 # s.sendto('hey!!'.encode(), ('192.168.30.35', 9527)) # 发送字符为中文,给encode()加入参数 msg = 'hey!!你好呀' s.sendto(msg.encode(encoding='gbk'), ('192.168.30.35', 9527)) s.close()
UDP接收
- 在发送数据的时候,无需绑定端口号
- 在接收数据的时候,才需要绑定端口号
- Udp程序通过recvfrom接收信息
import socket # 创建一个数据报套接字 用于UDP传输 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 绑定地址和端口号 # 参数是一个元素 第一个元素是地址,第二个元素是端口号 # 不写则让系统自取便可 s.bind(('', 52077)) # recvfrom # 返回值1 content 接收到的信息 # 返回值2 info 发送方的地址+端口号 while 1: content, info = s.recvfrom(1024) print(content) print(info) #content才是我们要的信息 print(content.decode(encoding='gbk')) s.close()
输出结果:
b'hey hey xbaxd9 xbaxd9' ('192.168.30.35', 9527) hey hey 嘿 嘿
发送和接收的原理:
在python中通过网络接收到的数据都是字节流,需要通过decode()解码后才能变成我们能够阅读的文字
UDP广播
只有UDP才能发送广播,TCP不能发送
如果要发送广播消息,需要通过setsockopt允许当前套接字发送广播数据
import socket # 创建一个数据报套接字 用于UDP传输 s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # 允许当前套接字发送广播 s.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1) # 目标地址,发送到局域网各子机 dest = ('<broadcast>',9527) msg = 'Hey!大家好,三姑六婆大家好' s.sendto(msg.encode(encoding='gbk'),dest) s.close()
学习文档: