Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。
基于文件类型的套接字家族
套接字家族的名字:AF_UNIX
unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信
基于网络类型的套接字家族
套接字家族的名字:AF_INET
服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束
socket()模块函数用法
import socket
# socket实例类
serve=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
serve.bind(('127.0.0.1',12))
# serve.bind('127.0.0.1',端口)
# 127.0.0.1这叫回送地址 表示电脑本身
# 端口 为普通整数
# 参数为一个元组
serve.listen()
# 监听
# 接收链接请求
# 第一个是表示客户端的socket 第二个客户端的地址信息
client,addr=serve.accept()
serve.recv(10)
# 接收数据 单位为字节
serve.close()
# 关闭数据
socket服务端
import socket
# 作为服务器,ip和端口号是明确的
# 参数1指定 AF_INET 为网络类型 , AF_UNIX 为文件类型
# 参数2 指定SOCK_STERAM 表示TCP协议 SOCK_DGRAM 为udp协议
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 默认就是网络类型 TCP协议
# serve = socket.socket()
server.bind(('127.0.0.1', 122))
# 开始监听1688端口
server.listen()
# 接收链接请求
# 第一个是表示客户端的socket 第二个客户端的地址信息
client,addr=server.accept()
data=client.recv(122)
client.send('222222'.encode('utf-8'))
server.close()
# 关机
socket客户端
常见的异常
服务端
import socket
client=socket.socket()
# 所有系统会自动分配随机端口给客户端
client.connect(('127.0.0.1', 122))
# 开始通话
# 发送数据 注意发送的内容只能是二进制 bytes
client.send('111111111'.encode('utf-8'))
data = client.recv(122)
client.close()
import socket
sever = socket.socket()
sever.bind(('127.0.0.1', 133))
sever.listen()
# accept 是一个阻塞函数 会一直等到有客户端链接过来 在继续执行
client,addr=sever.accept()
print('三次握手成功')
# 收发数据 注意都是用表示客户端的socket来收发数据
# client.send('hello'.encode('utf-8'))
try:
data=client.recv(100)
print('客户端发来的数据',data)
except:
print('client 下线')
client .close()
print('完成四次挥手')
# 休10秒
import time
time.sleep(10)
sever.close()
print('服务器关机')
客户端
import socket
client=socket.socket()
# connect本质实在进行三次握手 也是一个数据传输的过程 如果服务器没有立马响应 也会阻塞
client.connect(('127.0.0.1',133))
print('握手成功!')
# 发送数据 本质上是把数据交给操作系统来进行发送 一旦数据交给了操作系统 后续的发送
# 应用程序就无法控制了 ,send一般不会卡 当然 如果数据量很大就会阻塞
# client.send('hello'.encode('utf-8'))
# print('发送完成')
# 是从操作系统缓存区读取数据 如果当前还没有任何数据 就会进入阻塞
# 会一直等到有数据到来 再继续执行
try:
data=client.recv(100)
print('客户端的数据',data)
except:
print('client 下线')
# 客户端执行close 是正常关闭链接 会给服务器送空字节 用于表示要断开链接
client.close()
print('客户端关机')
import socket
server = socket.socket()
server.bind(('127.0.0.1',11))
server.listen()
server.accept()
server.close()
异常
# 如果已经开启了服务器 再次运行将会抛出 端口占用异常 把之前开启的服务器关掉即可
2.三次握手或四次挥手时,发生了异常导致对方程序已经结束而服务器任然处于time_wait状态导致!
3.在高并发的场景下,由于链接的客户端太多,也会产生大量处于time_wait状态的链接
"""
有些情况 明明已经关闭了进程 但是 还是端口占用
可能是进程正在后台运行 可以通过端口查出进程 进行关闭
windows下
netstat -ano | findstr 9898
tasklist | findstr 进程id 拿到进程名称
taskkill /f /t /im 进程名称
大招: 重启电脑
"""
循环
服务器
import socket
sever = socket.socket()
# 指定服务器的端口和ip 客户端的端口系统自动分配的
sever.bind(('127.0.0.1',36))
sever.listen()
while True:
client_socket,client_addr=sever.accept()
buffer_size=1024
# 缓冲区 就是一个临时的容器
while True:
try:
data=client_socket.recv(1024)
if not data:
client_socket.close()
break
print(data.decode('utf-8'))
# 解码时必须保证双方同意编码方式
# 转为大写在发回去
client_socket.send(data.upper())
except ConnectionResetError as a:
print('%s %s" % (client_addr[0],client_addr[1]),e')
# 如果对方下线了 那服务器也应该关闭对应的客户端对象
client_socket.close()
break
客户端
import socket
client=socket.socket()
client .connect(('127.0.0.1',36))
while True:
msg=input('输入内容...')
if msg == 'q':
break
if not msg:
continue
client.send(msg.encode('utf-8'))
print('发送')
data = client.recv(1024)
print(data.decode('utf-8'))
client.close()
windows正常关闭
服务器
import socket
sever = socket.socket()
sever.bind(('127.0.0.1',96))
sever.listen()
while True:
client_socket,client_addr=sever.accept()
buffer_size=1024
while True:
try:
data=client_socket.recv(1024)
if not data:
print(data)
break
print('收到数据...',data.decode('utf-8'))
# 解码时必须保证双方同意编码方式
# 转为大写在发回去
client_socket.send(data.upper())
except ConnectionResetError as a:
print('%s %s'%(client_addr[0],client_addr[1]),a)
# 如果对方下线了 那服务器也应该关闭对应的客户端对象
break
client_socket.close()
客户端
import socket
client=socket.socket()
client.connect(('127.0.0.1',96))
# 添加循环 用来重复收发数据
while True:
# 收发的顺序 必须和对面相反 否则卡死了
msg= input('输入内容....q 退出')
if msg == 'q':
break
if not msg:
continue
client.send(msg.encode('utf-8'))
print('发送')
data = client.recv(1024)
print(data.decode('utf-8'))
client.close()