网络编程基础之Socket套接字简单应用
一、Socket套接字实现通信循环
所谓通信循环,简单理解就是客户端可以给服务端循环发送信息并获得反馈的过程。
1、基础版
通信循环的程序分为两部分,即两个python模块,分别为客户端.py和服务端.py
第一部分:服务端.py
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong
import socket
phone = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) # 实例化了一个对象,phone即是一个套接字对象
phone.bind(('127.0.0.1',3301)) # 绑定指定IP和端口
phone.listen(5) # 开机,监听
conn,client = phone.accept() # 等待链接,并将获取的链接赋给conn和client,conn是另一个套接字对象
while True:
data = conn.recv(1024) # 收讯息
print('收到来自客户端的讯息:',data)
conn.send(data.title()) # 发送讯息
conn.close() # 关闭链接
phone.close() # 关机
第二部分:客户端.py
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong
import socket
phone = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) # 实例化了一个对象,phone即是一个套接字对象
# SOCK_STREAM 指的是TCP协议(或称流式协议)
# SOCK_DGRAM 指的是UDP协议(或称数据报协议)
phone.connect(('127.0.0.1',3301)) # 链接指定IP和端口的服务端
while True:
mes = input('在此输入>>:').strip()
phone.send(mes.encode('utf-8')) # 发讯息
data = phone.recv(1024) # 收讯息
print('收到来自服务端的消息:',data.decode('utf-8'))
phone.close() # 关机
2、改进版
上面的程序代码其实是存在bug的,比如没有对用户未输入和输入错误等进行异常处理,改进后的程序代码如下:
第一部分:服务端.py
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong
import socket
phone = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) # 实例化了一个对象,phone即是一个套接字对象
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # 端口重用, 解决程序关闭后端口仍然占用的情况
phone.bind(('127.0.0.1',3301)) # 绑定指定IP和端口
phone.listen(5) # 开机,监听
conn,client = phone.accept() # 等待链接,并将获取的链接赋给conn和client,conn是另一个套接字对象
while True:
try:
data = conn.recv(1024) # 收讯息
if not data:break # 仅适用于linux系统
print('收到来自客户端的讯息:',data)
conn.send(data.title()) # 发送讯息
except ConnectionResetError: # 适用于windows系统
break
conn.close() # 关闭链接
phone.close() # 关机
第二部分:客户端.py
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong
import socket
phone = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) # 实例化了一个对象,phone即是一个套接字对象
phone.connect(('127.0.0.1',3301)) # 链接指定IP和端口的服务端
while True:
mes = input('在此输入>>:').strip()
if not mes:continue # 防止未输入
phone.send(mes.encode('utf-8')) # 发讯息
data = phone.recv(1024) # 收讯息
print('收到来自服务端的消息:',data.decode('utf-8'))
phone.close() # 关机
二、Socket套接字实现链接循环
现在我们不满足于简单地通信循环了,我们的需求增加了链接循环,要求程序不光可以进行通信循环,还可以进行链接循环。
链接循环:我的理解就是服务端一直保持运行,而客户端可以在多个间切换分别与服务端进行连接(简而言之,就是多个客户端与一个服务端间的通信)。
增加功能后,改变的主要是服务端.py,程序同样是分为两部分。
第一部分:服务端.py
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong
import socket
phone = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) # 实例化了一个对象,phone即是一个套接字对象
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # 端口重用, 解决程序关闭后端口仍然占用的情况
phone.bind(('127.0.0.1',3301)) # 绑定指定IP和端口
phone.listen(5) # 开机,监听
while True: # 链接循环
conn,client = phone.accept() # 等待链接,并将获取的链接赋给conn和client,conn是另一个套接字对象
while True: # 通信循环
try:
data = conn.recv(1024) # 收讯息
if not data:break # 仅适用于linux系统
print('收到来自客户端的讯息:',data)
conn.send(data.title()) # 发送讯息
except ConnectionResetError: # 适用于windows系统
break
conn.close() # 关闭链接
phone.close() # 关机
'''
同时有多个客户端发送请求时,链接循环条件下服务端只能一次执行一个,服务端可以一直执行,只有当此客户端结束运行,
才能继续执行另一客户端的请求,以此类推客户端1结束后,客户端2执行,2结束,3才执行
'''
第二部分:客户端.py
客户端1.py
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong
import socket
phone = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) # 实例化了一个对象,phone即是一个套接字对象
phone.connect(('127.0.0.1',3301)) # 链接指定IP和端口的服务端
while True:
mes = input('在此输入>>:').strip()
if not mes:continue # 防止未输入
phone.send(mes.encode('utf-8')) # 发讯息
data = phone.recv(1024) # 收讯息
print('收到来自服务端的消息:',data.decode('utf-8'))
phone.close() # 关机
客户端2.py
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong
import socket
phone = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) # 实例化了一个对象,phone即是一个套接字对象
phone.connect(('127.0.0.1',3301)) # 链接指定IP和端口的服务端
while True:
mes = input('在此输入>>:').strip()
if not mes:continue # 防止未输入
phone.send(mes.encode('utf-8')) # 发讯息
data = phone.recv(1024) # 收讯息
print('收到来自服务端的消息:',data.decode('utf-8'))
phone.close() # 关机
客户端3.py
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong
import socket
phone = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) # 实例化了一个对象,phone即是一个套接字对象
phone.connect(('127.0.0.1',3301)) # 链接指定IP和端口的服务端
while True:
mes = input('在此输入>>:').strip()
if not mes:continue # 防止未输入
phone.send(mes.encode('utf-8')) # 发讯息
data = phone.recv(1024) # 收讯息
print('收到来自服务端的消息:',data.decode('utf-8'))
phone.close() # 关机
三、ssh远程执行命令
1、几点预备知识
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong
import os
'''
windows下测试:
dir:查看某一个文件夹下的子文件名和文件夹名
ipconfig :查看本地网卡的IP信息
tasklist:查看运行的进程
'''
# 执行系统命令,并拿到命令的结果
res = os.system('dir')
res = os.system('ipconfig')
print('命令结果:',res) # 命令结果: 0 ,0表示执行成功,非0表示失败
import subprocess
obj = subprocess.Popen('dir',shell=True,
stdout=subprocess.PIPE, # 获取'dir'命令执行正确时的返回信息
stderr=subprocess.PIPE) # # 获取错误命令执行时的返回信息
print(obj) # <subprocess.Popen object at 0x00000252715E70F0>
print('正确时执行stdout>>:',obj.stdout.read().decode('gbk')) # 因为执行的是windows系统的命令,默认编码是gbk, read()获取的是bytes数据,需要decode解码转为操作系统可读的
print('错误时执行stderr>>:',obj.stderr.read().decode('gbk')) # 如果是linx系统,则默认是utf-8
2、核心程序仍然分为两部分
服务端.py
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong
import socket
import subprocess
phone = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) # 实例化一个套接字对象
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # 端口重用,解决程序结束而端口仍被占用的情况
phone.bind(('127.0.0.1',3301)) # 绑定IP和端口
phone.listen(5) # 监听
while True:
conn,client = phone.accept() # 获取链接对象和IP、端口
while True: # 通讯循环
try: # 适用于windows系统
# 1、接受命令
cmd = conn.recv(1024)
if not cmd:break # 适用于linux系统
print('收到来自客户端的命令:',cmd.decode('gbk')) # 打印接收到的命令
# 2、执行命令
obj = subprocess.Popen(cmd.decode('gbk'),shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
print(obj)
# 3、返回命令执行后的结果
stdout = obj.stdout.read() # 命令执行正确时结果
stderr = obj.stderr.read() # 错误命令执行的结果
conn.send(stdout+stderr) # 返回执行命令的结果
except ConnectionResetError:
break
conn.close()
phone.close()
客户端.py
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong
import socket
phone = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) # 创建套接字对象
phone.connect(('127.0.0.1',3301)) # 建立链接
while True: # 通信循环
cmd = input('输入命令>>:').strip()
if not cmd:continue
phone.send(cmd.encode('gbk')) # 发送命令
data = phone.recv(1024) # 接收信息
print('接收来自服务端的信息:',data.decode('gbk')) # 打印接收的信息
phone.close() # 关机
读书原为修身,正己才能正人正世;不修身不正己而去正人正世者,无一不是盗名欺世;你把念过的书能用上十之一二,就是很了不得的人了。——朱先生