一、什么是套接字socket
我们知道,网络通信都是基于TCP/IP协议族的协议实现,这些协议的控制实现使用需要很复杂的底层逻辑和代码,对于应用程序来说,不可能每次都写一套复杂的代码来实现网络通信,socket的作用就是位于应用程序和TCP/IP协议之间,为应用程序提供操作TCP/IP的标准接口。我们在实现网络通信的时候,只需要通过操作socket即可。
PS:网络通信都是基于TCP和UDP,所以实现网络通信也就是实现TCP和UDP。
二、socket的工作逻辑
既然是通信,那就有双方才能通信,需要有一方作为服务端,一方作为客户端。服务端和客户端通信过程如下(借用大佬的图):
服务端先建立一个Socket,然后绑定端口,并监听该端口,等待客户端连接;这时候若客户端也建立了一个Socket,并连接服务器,如果连接成功,则客户端与服务端的连接建立。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接。完成一次socket通信。
三、socket通信的的Python实现
socket通信是应用程序实现网络通信的基础,所以几乎每一种语言都有实现socket的库,可以使用任何一种语言实现socket通信。python也有一个socket模块,可以用来实现socket通信。
1.python socket模块的函数和方法
(1) 建立socket对象
s=socket.socket(family,type,ptoto)
参数说明:
family = socket.AF_INET---AF_INET表示使用IPv4
type = socket.SOCK_STREAM(TCP连接)或socket.SOCK_DGRAM(UDP连接)
proto 一般不填
(2)服务端函数
s.bind() 绑定主机,端口号
s.listen() 开始TCP监听
s.accept() 接受TCP客户的连接,(阻塞式)等待连接的到来
(3) 客户端函数
s.connect() 初始化socket,发起连接
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常
(4)公共套接字函数
*收发TCP数据*
s.recv() 接收TCP数据
s.send() 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,丢弃多余数据,不会发完)
s.sendall() 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
*收发UDP数据*
s.recvfrom() 接收UDP数据
s.sendto() 发送UDP数据
*其他*
s.getpeername() 连接到当前套接字的远端的地址
s.getsockname() 当前套接字的地址
s.getsockopt() 返回指定套接字的参数
s.setsockopt() 设置指定套接字的参数
s.close() 关闭套接字
(5)获取本机域名和IP、端口
socket.gethostname() 获取本地计算机名
socket.gethostbyname('域名') 获取域名对应的IP地址 socket.gethostbyname_ex('域名') 得到域名对应的一个三元素元组,分别是查询域名、同一IP地址下的域名列表、同一主机同一接口的IP地址列表
socket.gethostbyaddr('IP地址') 得到IP对应的一个三元素元组,分别是查询域名、同一IP地址下的域名列表、同一主机同一接口的IP地址列表
getservbyname(service,protocol) 获取服务所使用的端口号
inet_aton(ip_addr) IP地址转为数据包
inet_ntoa( packed) 数据包转为IP地址
注:非Python程序以32位字节包的形式存储和使用IP地址,上边两个函数用来对它们进行相互转换
INADDR_ANY:任意IP地址
INADDR_BROADCAST:广播地址
INADDR_LOOPBACK:本地回环地址
(6) 面向锁的套接字方法
s.setblocking() 设置套接字的阻塞与非阻塞模式
s.settimeout() 设置阻塞套接字操作的超时时间
s.gettimeout() 得到阻塞套接字操作的超时时间
(7) 面向文件的套接字方法
s.fileno() 套接字的文件描述符
s.makefile() 创建一个与该套接字相关的文件
2.socket通信基本实现
socket通信的过程,简而言之就是客户端发起连接,服务器端监听和接受连接的过程
1. 服务器端代码(TCP连接):
import socket #加载socket模块
server=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #建立socket对象,对象名为server
host='192.168.1.106' #定义服务端ip
port=9999 #定义服务端端口
server.bind((host,port)) #绑定主机和端口(注意:两个括号)
server.listen(1) #监听连接,括号中数字为设定的最大连接数,超过后排队
conn,addr=server.accept() #等待连接,并在连接建立后接收数据。返回一个建立的连接对象和客户端地址
msg_r=conn.recv(1024) #接收消息(括号内为给接收数据准备的缓存空间大小)
print(msg_r.decode('utf-8') #解码接收的数据并打印
msg_s='02,02,我是01!' #定义要发送的数据
conn.send(msg_s.encode('utf-8')) #发送消息,必须进行编码,接收消息时再解码
server.close() #关闭整个会话
2. 客户端代码
import socket #加载socket模块
client=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #建立socket对象,对象名为client
host='192.168.1.106' #定义服务端ip
port=9999 #定义服务端端口
client.connect((host,port)) #连接服务端(注意:两个括号)
msg_s='01,01,我是02!' #定义要发送的数据
client.send(msg_s.encode('utf-8')) #发送消息。需进行编码,接收消息时再解码
msg_r=client.recv(1024) #接收消息(括号内为给接收数据准备的缓存空间大小)
print(msg_r.decode('utf-8') #解码接收的数据并打印
client.close() #关闭会话
参考链接:
Socket原理讲解