简介
socket是应用层与TCP/IP协议通信的中间的软件抽象层,它是一组接口。把复杂的TCP/IP协议足隐藏在接口后面,对用户来说,一组简单的接口就是全部,socket去组织数据,以符合指定的协议
- recv在缓冲区为空时,阻塞
- recvfrom在缓冲区为空时,接收为空的字节
基于文件的套接字 AF_UNIX
基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在统一机器,可以通过访问同一个文件系统间接完成通信~
基于网络类型的套接字 AF_INET
基于网络作为介质实现通信,还有AD_INET6,被用于ipv6等其它网络类型套接字
示意图
TCP客户端 TCP服务端
socket() socket()
| ↓
| bind()
| ↓
| listen()
↓ ↓
connect() <--建立连接--> accept()
↓ ↓ 阻塞,直到有客户端连接
write() <--请求数据--> read()
↓ ↓ 处理请求
read() <--回应数据--- write()
↓ ↓
close() ---结束连接--> read()
↓
close()
TCP传输套接字
简单示例
服务端
# -*- coding:utf8 -*-
import socket
test = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#定义socket通信方式和通信协议。socket.AF_INET基于网络通信,socket.SOCK_STREAM基于TCP协议
test.bind(('127.0.0.1',8000)) #定义通信ID
test.listen(5) #定义最大通信监听数
conn,addr = test.accept() #定义对话连接
msg = conn.recv(1024) #定义接收字节信息
print('客户端发送的消息是:',msg)
conn.send(msg.upper()) #定义发送消息
conn.close() #连接关闭
test.close() #程序关闭
客户端发送的消息是: b'hello'
客户端
# -*- coding:utf8 -*-
import socket
test = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#定义socket通信方式和通信协议。socket.AF_INET基于网络通信,socket.SOCK_STREAM基于TCP协议
test.connect(('127.0.0.1',8000)) #定义通信ID,服务器的地址和端口
test.send('hello'.encode('utf-8')) #定义发送内容
data = test.recv(1024) #定义接收字节信息
print('收到服务端的发来的消息是:',data)
收到服务端的发来的消息是: b'HELLO'
TCP网络传输套接字示例
原示例
import socket
test = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
优化示例
form socket import *
test = socket(AF_INET,SOCK_STREAM)
==也可以将值以变量形式写入到配置文件中导入==
服务端优化示例
# -*- coding:utf8 -*-
from socket import *
test = socket(AF_INET,SOCK_STREAM)
ip_port = ('127.0.0.1',8000)
back_log = 5
buffer_size = 1024
test.bind(ip_port) #定义通信ID
test.listen(back_log) #定义最大通信监听数
conn,addr = test.accept() #定义对话连接
msg = conn.recv(1024) # 定义接收字节信息
print('客户端发送的消息是:',msg)
conn.send(msg.upper()) #定义发送消息
conn.close() #连接关闭
test.close() #程序关闭
循环发送示例
服务端
# -*- coding:utf8 -*-
from socket import *
tcp_servive = socket(AF_INET,SOCK_STREAM)
ip_port = ('127.0.0.1',8000)
back_log = 5
buffer_size = 1024
tcp_servive.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #防止服务端再次启用导致端口被占用错误
tcp_servive.bind(ip_port) #定义通信ID
tcp_servive.listen(back_log) #定义最大通信监听数
while True:
print("服务端程序运行中。。。")
conn, addr = tcp_servive.accept() #定义对话连接(循环收发消息)
while True:
try: #客户端异常断开处理
msg = conn.recv(buffer_size) #定义接收字节信息
print('客户端发送的消息是:',msg.decode('utf-8'))
conn.send(msg.upper()) #定义发送消息
except Exception:
print("客户端强制断开!")
break
conn.close() #连接关闭
tcp_servive.close() #程序关闭
客户端
# -*- coding:utf8 -*-
from socket import *
ip_port = ('127.0.0.1',8000)
buffer_size = 1024
tcp_client = socket(AF_INET,SOCK_STREAM)
tcp_client.connect(ip_port) #定义通信ID,服务器的地址和端口
while True:
msg = input(">>>请输入需要发送的消息!".strip())
if not msg:continue #判断值是否为空
tcp_client.send(msg.encode('utf-8')) #定义发送内容
print('客户端已经发送消息:',msg)
data = tcp_client.recv(buffer_size) #定义接收字节信息
print('收到服务端的发来的消息是:', data.decode('utf-8'))
tcp_client.close()
TCP协议远程执行命令示例
粘包特性
服务端
from socket import *
import subprocess
ip_port = ('127.0.0.1',8080)
back_log = 5
buffer_size = 4096
tcp_server = socket(AF_INET,SOCK_STREAM)
tcp_server.bind(ip_port)
tcp_server.listen(back_log)
while True:
conn,addr=tcp_server.accept() #建立连接
print('新的客户端链接',addr)
while True:
#接收信息
try:
cmd=conn.recv(buffer_size)
if not cmd:break
print('收到客户端的命令',cmd.decode('utf-8'))
#执行命令
res=subprocess.Popen(cmd.decode('utf-8'),shell=True,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
stdin=subprocess.PIPE)
err=res.stderr.read()
if err:
cmd_res=err
else:
cmd_res=res.stdout.read()
#发送信息
if not cmd_res:
cmd_res='执行成功'.encode('gbk')
conn.send(cmd_res)
except Exception as e:
print(e)
break
客户端
from socket import *
ip_port = ('127.0.0.1',8080)
back_log = 5
buffer_size = 4096
tcp_client = socket(AF_INET,SOCK_STREAM)
tcp_client.connect(ip_port)
while True:
cmd=input('>>请输入需要执行的命令: ').strip()
if not cmd:continue
if cmd == 'quit':break
tcp_client.send(cmd.encode('utf-8'))
cmd_res=tcp_client.recv(buffer_size)
print('命令的执行结果是 ',cmd_res.decode('gbk'))
tcp_client.close()
UDP网络传输套接字
简单示例
服务端
udp_service = socket() #创建一个服务器套接字
udp_service.bind() #绑定服务器套接字
while True: #服务器通讯循环
udp_service.recvfrom() #服务端接收消息
udp_sendto.recvfrom() #服务端发送消息
udp_service.close() #关闭服务端套接字
客户端
udp_client = socket() #创建一个客户端套接字
while True: #客户端通讯循环
udp_service.recvfrom() #服务端接收消息
udp_sendto.recvfrom() #服务端发送消息
udp_client.close() #关闭客户端套接字
UDP网络传输套接字示例示例
服务端示例
# -*- coding:utf-8 -*-
from socket import *
ip_port = ('127.0.0.1',8080) #定义通信ID
buffer_size = 4096 #定义接收字节信息
udp_service = socket(AF_INET,SOCK_DGRAM) #定义socket通信方式和通信协议。socket.AF_INET基于网络通信,socket.SOCK_STREAM基于TCP协议
udp_service.bind(ip_port) #通信ID
print("服务端运行中...")
while True:
msg,addr = udp_service.recvfrom(buffer_size) #定义接收字节信息(元组形式)
print("接收到的消息是:",msg.decode('utf-8')) #打印接受到的字节信息
udp_service.sendto(msg.upper(),addr) #返回并修改传输值
客户端示例
# -*- coding:utf-8 -*-
from socket import *
ip_port = ('127.0.0.1',8080) #定义通信ID
buffer_size = 4096 #定义接收字节信息
udp_client = socket(AF_INET,SOCK_DGRAM) #定义socket通信方式和通信协议。socket.AF_INET基于网络通信,socket.SOCK_STREAM基于TCP协议
while True:
msg = input(">>>请输入您要发送的内容".strip())
udp_client.sendto(msg.encode('utf-8'),ip_port) #定义发送内容和到达地址
msg,addr = udp_client.recvfrom(buffer_size) #定义接收字节信息(元组形式)
print(msg.decode('utf-8')) #打印返回的字节信息
UDP协议远程执行命令示例
不粘包特性
服务端
from socket import *
import subprocess
ip_port=('127.0.0.1',8080)
back_log=5
buffer_size=4096
udp_server=socket(AF_INET,SOCK_DGRAM)
udp_server.bind(ip_port)
while True:
#接收消息
cmd,addr=udp_server.recvfrom(buffer_size)
# 执行命令,得到命令的运行结果cmd_res
res = subprocess.Popen(cmd.decode('utf-8'), shell=True,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
stdin=subprocess.PIPE)
err = res.stderr.read()
if err:
cmd_res = err
else:
cmd_res = res.stdout.read()
if not cmd_res:
cmd_res='执行成功'.encode('gbk')
#发送消息
udp_server.sendto(cmd_res,addr)
客户端
from socket import *
ip_port=('127.0.0.1',8080)
back_log=5
buffer_size=4096
udp_client=socket(AF_INET,SOCK_DGRAM)
while True:
cmd=input('>>请输入需要执行的命令: ').strip()
if not cmd:continue
if cmd == 'quit':break
udp_client.sendto(cmd.encode('utf-8'),ip_port)
cmd_res,addr=udp_client.recvfrom(buffer_size)
print('命令的执行结果是 ',cmd_res.decode('gbk'),end='')
udp_client.close()