day 36 基于tcp协议的套接字通信
1 套接字
1.1 引入
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的。


也有人将socket说成ip+port,ip是用来标识互联网中的一台主机的位置,而port是用来标识这台机器上的一个应用程序,ip地址是配置到网卡上的,而port是应用程序开启的,ip与port的绑定就标识了互联网中独一无二的一个应用程序
而程序的pid是同一台机器上不同进程或者线程的标识
1.2 套接字工作流程
一个生活中的场景。你要打电话给一个朋友,先拨号,朋友听到电话铃声后提起电话,这时你和你的朋友就建立起了连接,就可以讲话了。等交流结束,挂断电话结束此次交谈。 生活中的场景就解释了这工作原理。

2 基于tcp协议的简单套接字通信
2.1 服务端
import socket
# 1、买手机
phone=socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 流式协议=》tcp协议
# 2、绑定手机卡
phone.bind(('127.0.0.1',8081)) # 0-65535, 1024以前的都被系统保留使用
# 3、开机
phone.listen(5) # 5指的是半连接池的大小
print('服务端启动完成,监听地址为:%s:%s' %('127.0.0.1',8080))
# 4、等待电话连接请求:拿到电话连接conn
conn, client_addr = phone.accept()
print("客户端的ip和端口:",client_addr)
# 5、通信:收\发消息
data=conn.recv(1024) # 最大接收的数据量为1024Bytes,收到的是bytes类型
print("客户端发来的消息:",data.decode('utf-8'))
conn.send(data.upper())
# 6、关闭电话连接conn(必选的回收资源的操作)
conn.close()
# 7、关机(可选操作)
phone.close()
2.2 客服端
import socket
#1、买手机
phone=socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 流式协议=》tcp协议
#2、拨通服务端电话
phone.connect(('127.0.0.1',8081))
#3、通信
import time
time.sleep(10)
phone.send('hello egon 哈哈哈'.encode('utf-8'))
data=phone.recv(1024)
print(data.decode('utf-8'))
#4、关闭连接(必选的回收资源的操作)
phone.close()
2.3 问题:有的同学在重启服务端时可能会遇到

解决方法1:改端口,重启
解决方法2:加入一条socket配置,重用ip和端口
import socket
from socket import SOL_SOCKET,SO_REUSEADDR
sk = socket.socket()
sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
sk.bind(('127.0.0.1',8898)) #把地址绑定到套接字
sk.listen() #监听链接
conn,addr = sk.accept() #接受客户端链接
ret = conn.recv(1024) #接收客户端信息
print(ret) #打印客户端信息
conn.send(b'hi') #向客户端发送信息
conn.close() #关闭客户端套接字
sk.close() #关闭服务器套接字(可选)
3 加上通信循环
3.1 服务端
点击查看代码
import socket
# 1、买手机
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 流式协议=》tcp协议
# 2、绑定手机卡
phone.bind(('127.0.0.1',8083)) # 0-65535, 1024以前的都被系统保留使用
# 3、开机
phone.listen(5) # 5指的是半连接池的大小
print('服务端启动完成,监听地址为:%s:%s' %('127.0.0.1',8080))
# 4、等待电话连接请求:拿到电话连接conn
conn,client_addr=phone.accept()
# 5、通信:收\发消息
while True:
try:
data=conn.recv(1024) # 最大接收的数据量为1024Bytes,收到的是bytes类型
if len(data) == 0:
# 在unix系统洗,一旦data收到的是空,意味着是一种异常的行为:客户度非法断开了链接
break
print("客户端发来的消息:",data.decode('utf-8'))
conn.send(data.upper())
except Exception:
# 针对windows系统
break
# 6、关闭电话连接conn(必选的回收资源的操作)
conn.close()
# 7、关机(可选操作)
phone.close()
3.2 客服端
点击查看代码
import socket
#1、买手机
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 流式协议=》tcp协议
#2、拨通服务端电话
phone.connect(('127.0.0.1',8083))
#3、通信
while True:
msg=input("输入要发送的消息>>>: ").strip() #msg=''
if len(msg) == 0:
continue
phone.send(msg.encode('utf-8'))
print('======?')
data=phone.recv(1024)
print(data.decode('utf-8'))
#4、关闭连接(必选的回收资源的操作)
phone.close()
4 加上链接循环
4.1 服务端
点击查看代码
服务端应该满足的特点:
1、一直提供服务
2、并发地提供服务
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
import socket
# 1、买手机
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 流式协议=》tcp协议
# 2、绑定手机卡
phone.bind(('127.0.0.1',8080)) # 0-65535, 1024以前的都被系统保留使用
# 3、开机
phone.listen(5) # 5指的是半连接池的大小
print('服务端启动完成,监听地址为:%s:%s' %('127.0.0.1',8080))
# 4、等待电话连接请求:拿到电话连接conn
while True:
conn,client_addr=phone.accept()
# 5、通信:收\发消息,加上链接循环,实现并发
while True:
try:
data=conn.recv(1024) # 最大接收的数据量为1024Bytes,收到的是bytes类型
if len(data) == 0:
# 在unix系统洗,一旦data收到的是空,意味着是一种异常的行为:客户度非法断开了链接
break
print("客户端发来的消息:",data.decode('utf-8'))
conn.send(data.upper())
except Exception:
# 针对windows系统
break
# 6、关闭电话连接conn(必选的回收资源的操作)
conn.close()
7、关机(可选操作)
phone.close()
4.2 客服端,连续打开多个
点击查看代码
import socket
#1、买手机
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 流式协议=》tcp协议
#2、拨通服务端电话
phone.connect(('127.0.0.1',8083))
#3、通信
while True:
msg=input("输入要发送的消息>>>: ").strip() #msg=''
if len(msg) == 0:
continue
phone.send(msg.encode('utf-8'))
print('======?')
data=phone.recv(1024)
print(data.decode('utf-8'))
#4、关闭连接(必选的回收资源的操作)
phone.close()
5 基于udp协议的套接字通信
5.1 服务端
import socket
server=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # 数据报协议=》udp协议
server.bind(('127.0.0.1',8081))
while True:
data,client_addr=server.recvfrom(1024)
server.sendto(data.upper(),client_addr)
server.close()
5.2 客服端
import socket
client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # 流式协议=》tcp协议
while True:
msg=input('>>>: ').strip()
client.sendto(msg.encode('utf-8'),('127.0.0.1',8081))
res=client.recvfrom(1024)
print(res)
client.close()

浙公网安备 33010602011771号