一、Socket介绍
1、什么是socket?
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部。
当你想给另一台计算机发消息,你知道他的IP地址,而他的机器上运行着多个软件,如QQ、迅雷等,那当你通过qq发消息给他时,消息通过ip地址到达他的电脑,那他的电脑怎样把消息给指定的QQ程序呢?答案就是port,即端口,一个机器上可以有66535个端口,你的程序要想从网络上收发数据,必须绑定一个端口,这样,远程设备发到这个端口上的数据,就会转给这个程序。
如下图所示:
2、socket通信
当两台机器通过socket建立连接后,主要做两件事,一个是收数据,一个是发数据,没数据时就等着。
· 我们可以通过打电话模拟这个过程:
打电话方(socket客户端)
1、你必须先有个电话(生成socket对象)
2、输入你想拨打的电话(connect 远程主机的ip和port)
3、等待对方接听
4、say"hello ,do you have time?"(send()发送消息)
5、等待回应-->响应回应-->等待回应...
接电话方(socket服务端)
1、同样首先你得有个电话(生成socket对象)
2、你需要绑定你的电话号码(绑定本机的ip和port)
3、你的电话必须接上电话线(连网)
4、等电话(监听电话 listen)
5、电话铃声响了,接听电话,听到“hello,do you have time?”(接受连接)
3、socket通信完整过程
二、Socket套接字方法
1、socket实例类
socket.socket(family=AF_INET,type=SOCK_STREAM)
family(socket家族)
socket.AF_UNIX:用于本机进程间通讯,为了保证程序安全,两个独立的程序(进程)间是不能互相访问彼此的内存的,但为了实现进程间的通讯,可以通过创建一个本地的socket来完成。
socket.AF_INET:还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,其他的很少用到,但是我们现在只关心网络编程,所以大部分时候只使用AF_INET。
socket type类型
socket.SOCK_STREAM 用于TCP
socket.SOCK_DGRAM 用于UDP
socket.SOCK_RAW 原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
socket.SOCK_RDM 是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
2、服务端套接字函数
s.bind() 绑定(主机,端口号)到套接字
s.listen() 开始TCP监听
s.accept() 被动接受TCP客户的连接,等待连接的到来
3、客户端套接字函数
s.connect() 初始化TCP服务器连接
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常。
4、公共的套接字函数
s.recv() 接收数据
s.send() 发送数据(当待发送数据大于己端缓存区剩余空间时,数据丢失,不会发完)
s.sendall() 发送完整的TCP数据(本质就是循环调用send,数据不丢失,直到发完)
s.recvfrom() 从套接字接收数据。返回值是一对(字节,地址)
s.getpeername() 连接到当前套接字的远端的地址
s.close() 关闭套接字
socket.getaddrinfo(host, port, family=0, type=0, proto=0, flags=0) 返回远程主机的地址信息,例子 socket.getaddrinfo('luffycity.com',80)
socket.getfqdn() 拿到本机的主机名
socket.gethostbyname() 通过域名解析ip地址
socket.setblocking(flag) #True or False,设置socket为非阻塞模式,io异步时会用
三、一个简单的socket套接字实例
# 服务端.py #!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong import socket
'''
在此服务端有两个套接字,一个是 phone 绑定,监听,获取链接;另一个是 conn 收发消息
而 客户端只有一个套接字,就是 phone
'''
#1、 买手机
tel = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
#2、绑定手机卡
tel.bind(('127.0.0.1',8081))
#3、开机
tel.listen(5)
#4、等待连通
conn,client = tel.accept()
#5、收发消息
data = conn.recv(1024)
print('收到来自客户端的消息',data) # 收到来自客户端的消息 b'hello world'
conn.send(data.upper())
#6、挂断
conn.close()
#7、关机
tel.close()
# 客户端.py #!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong import socket
# 1、买手机
phone = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) # 2、打电话(客户端无固定IP和端口,所有不需要绑定)
phone.connect(('127.0.0.1',8081)) # 3、发收消息
phone.send('hello world'.encode('utf-8'))
data = phone.recv(1024)
print('收到来自服务端的消息',data) # 收到来自服务端的消息 b'HELLO WORLD' # 4、关机
phone.close()