python之网络socket编程
一、网络协议
客户端/服务器架构
1.硬件C/S架构(打印机)
2.软件C/S架构(互联网中处处是C/S架构):B/S架构也是C/S架构的一种,B/S是浏览器/服务器
C/S架构与socket的关系:我们用socket就是为了完成C/S架构的开发
osi七层
引子:
须知一个完整的计算机系统是由硬件、操作系统、应用软件三者组成,具备了这三个条件,一台计算机系统就可以自己跟自己玩了(打个单机游戏,玩个扫雷啥的)
如果你要跟别人一起玩,那你就需要上网了,什么是互联网?
互联网的核心就是由一堆协议组成,协议就是标准,比如全世界人通信的标准是英语
如果把计算机比作人,互联网协议就是计算机界的英语。所有的计算机都学会了互联网协议,那所有的计算机都就可以按照统一的标准去收发信息从而完成通信了。
人们按照分工不同把互联网协议从逻辑上划分了层级,
详见网络通信原理:http://www.cnblogs.com/linhaifeng/articles/5937962.html
为何学习socket一定要先学习互联网协议?
首先C/S架构是基于网络通信的
然后网络的核心即一堆网络协议,也就是协议标准。如果你想开发一款基于网络通信的软件,就必须遵循这些标准

socke层

二、socket是什么?
socket是应用层与TCP/IP协议通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的。
三、基于TCP协议的socket
套接字的分类:
基于文件类型的套接字家族:AF_UNIX(在Unix系统上,一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程同时运行在同一机器,可以通过访问同一个文件系统间接完成通信)
基于网络类型的套接字家族:AF_INET (python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我们只使用AF_INET)
套接字的工作流程:
下面我们举个打电话的小例子来说明一下
如果你要给你的一个朋友打电话,先拨号,朋友听到电话铃声后提起电话,这时你和你的朋友就建立起了连接,就可以讲话了。等交流结束,挂断电话结束此次交谈。 生活中的场景就解释了这工作原理。
(如果你去一家餐馆吃饭,假设哪里的老板就是服务端,而你自己就是客户端,当你去吃饭的时候,你肯定的知道那个餐馆,也就是服务端的地址吧,但是对于你自己来说,餐馆的老板不需要知道你的地址吧)

套接字函数
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 1.服务端套接字函数
phone.bind('主机ip地址',端口号) #绑定到(主机,端口号)套接字
phone.listen() #开始TCP监听
phone.accept() #被动接受TCP客户的连接,等待连接的到来
服务端套接字函数
2.客户端套接字函数
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#买手机
phone.connect() #主动连接服务端的ip和端口
phone.connect_ex() #connect()函数的扩展版本,出错的时候返回错码,而不是抛出异常
客户端套接字函数
3.服务端和客户端的公共用途的嵌套字函数
phone.recv() #接受TCP数据
phone.send() #发送TCP数据
phone.recvfrom() #接受UDP数据
phone.sendto() #发送UDP数据
phone.getpeername() #接收到当前套接字远端的地址
phone.getsockname() #返回指定套接字的参数
phone.setsockopt() #设置指定套接字的参数
phone.close() #关闭套接字
服务端和客户端的公共用途的嵌套字函数
面向锁的套接字方法
phone.setblocking() #设置套接字的阻塞与非阻塞模式
phone.settimeout() #设置阻塞套接字操作的超时时间
phone.gettimeout() #得到阻塞套接字操作的超时时间
面向锁的套接字方法
面向文件的套接字函数
phone.fileno() # 套接字的文件描述符
phone.makefile() #创建一个与该套接字相关的文件
面向文件的套接字函数
TCP是基于链接的,必须先启动服务器,然后再启动客户端去链接服务端
服务端:
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#买手机
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #可以多次启动
#执行多次的时候会报错,那么怎么办呢、?就在绑卡前面加上上面那句setsockopt方法就ok了
phone.bind(('192.168.20.44',8080))#绑定手机卡(ip,端口)
# 端口号在1024以前的是系统用的,1024以后的都是你自己写的程序去定义的端口 print('starting run......')
phone.listen(5) #开机 5代表的是最多挂起5个,也可以好多个
while True: #链接循环
coon,client_addr=phone.accept()#等待接电话,(coon是建立的链接,客户端的ip和端口号组成的元组)
print(coon,client_addr) #收发消息
while True: #通信循环
try: #如果不加try...except ,就会报错,因为它不知道你什么时候断开链接的,服务器还以为你在运行
data = coon.recv(1024) #收了1024个字节的消息
print('client data 收到消息:%s'%data.decode('utf-8'))
coon.send(data.upper()) #发消息
except Exception: #因为你不知道客户端什么时候断开链接,
break
coon.close() #挂电话
phone.close() #关机 # 处理逻辑错误的两种方式:
# if 判断
# try...except 异常处理
# 异常处理
# 当你知道直接错误的条件时就用if判断了
# 当程序错误一定发生,但是你又预知不了它出错的条件是什么的时候,就用try...except
服务端
客户端:
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#买手机
phone.connect(('192.168.20.44',8080)) #直接连接服务端的ip和端口 # 发收消息
while True:
msg = input('>>:').strip() #用户输入
if not msg:continue #如果为空就继续输
phone.send(msg.encode('utf-8')) # 发送你输入的消息
# phone.send('hello'.encode('utf-8'))
data = phone.recv(1024) #在接收一下
print('server back res服务端返回结果:>>%s'%data.decode('utf-8')) phone.close()
客户端
注意:
如果你在重启服务端的时候可能遇到这样的问题:

这个是由于你的服务端仍然存在四次挥手的time_wait状态在占用地址(如果不懂,请深入研究1.tcp三次握手,四次挥手 2.syn洪水攻击 3.服务器高并发情况下会有大量的time_wait状态的优化方法)。那么怎么解决呢?你也可以这样的
#加入一条socket配置,重用ip和端口 phone=socket(AF_INET,SOCK_STREAM)
phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
5 phone.bind(('127.0.0.1',8080))
四、基于TCP协议模拟ssh远程执行命令
import socket
import subprocess
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#买手机
phone.bind(('192.168.20.44',8081))#绑定手机卡
phone.listen(5)#阻塞的最大个数
print('starting....')
while True:
conn,addr=phone.accept()#等待连接
print(addr,conn)
while True:
cmd=conn.recv(10240)#接收的最大值
# if not cmd :break
print('接收的是:%s'%cmd.decode('utf-8'))
#处理过程
res=subprocess.Popen(cmd.decode('utf-8'),shell=True, #Popen是执行命令的方法
stdout=subprocess.PIPE,
stderr=subprocess.PIPE )
stdout=res.stdout.read()
stuerr=res.stderr.read()
conn.send(stdout+stuerr)
conn.close()
phone.close()
服务端
import socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('192.168.20.44',8081))#绑定端口
while True:
cmd=input('>>请输入').strip()
if not cmd: continue
phone.send(cmd.encode('utf-8'))
data=phone.recv(10240)
print('返回的是%s'%data.decode('gbk'))
phone.close()
客户端
六、基于UDP协议的socket
from socket import *
udp_server = socket(AF_INET,SOCK_DGRAM)
udp_server.bind(('127.0.0.1',8080)) #绑定
while True:#通讯循环
msg,client_addr= udp_server.recvfrom(1024)
print('收到的消息是:%s'%msg.decode('utf-8'))
udp_server.sendto(msg.upper(),client_addr)
udp_server.close()
服务端
# udp 无链接,所以不需要连接
from socket import *
udp_client = socket(AF_INET,SOCK_DGRAM) while True:
msg = input('>>:').strip()
udp_client.sendto(msg.encode('utf-8'),('127.0.0.1',8080))
res,sever_addr = udp_client.recvfrom(1024)
print('返回的结果是:%s'%res.decode('utf-8'))
udp_client.close()
客户端
基于UDP协议的socket的应用(模拟QQ聊天)
from socket import *
udp_server= socket(AF_INET,SOCK_DGRAM)
udp_server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
udp_server.bind(('127.0.0.1',8080))
print('start running...') while True:
qq_msg,addr = udp_server.recvfrom(1024)
print('来自[%s:%s]的一条消息:\033[44m%s\033[0m'%(addr[0],addr[1],qq_msg.decode('utf-8')))
back_msg = input('回复消息:>>').strip()
udp_server.sendto(back_msg.encode('utf-8'),addr)
udp_server.close()
服务端
from socket import *
udp_client = socket(AF_INET,SOCK_DGRAM)
qq_name_dic = {
'房得成':('127.0.0.1',8080),
'陈凤琴':('127.0.0.1',8080),
'王雅玲':('127.0.0.1',8080),
'喜洋洋':('127.0.0.1',8080)
}
while True:
qq_name = input('请输入聊天对象:>>').strip()
if qq_name not in qq_name_dic: continue
while True:
msg = input('请输入消息,回车发送:').strip()
if msg=='quit':break
if not msg or not qq_name or qq_name not in qq_name_dic:continue
udp_client.sendto(msg.encode('utf-8'),qq_name_dic[qq_name])
back_msg,addr = udp_client.recvfrom(1024)
print('来自[%s:%s]的一条消息:\033[41m%s\033[0m'%(addr[0],addr[1],back_msg.decode('utf-8')))
udp_client.close()
客户端
运行结果截图


五、subprocess子进程模块
#subprocess import subprocess
#Popen方法是用来执行系统命令的,直接把结果打印到终端了
res =subprocess.Popen(r'dir',shell=True,
#r'dsfsdfr',shell=True,
# stdin= #标准输入(不常用)
stdout=subprocess.PIPE,#stdout 标准输出
stderr=subprocess.PIPE) #stderr 标准错误
# 拿到的是‘gbk’编码的结果,
# 这个命令可能有正确结果,也可能有错误结果
print(res.stdout.read().decode('gbk'))
print('========')
print(res.stdout.read().decode('gbk')) #说明只能读一次
print(res.stderr.read().decode('gbk')) #如果是错误的就会提示
六、struct模块
#该模块可以把一个类型,如数字,转成固定长度的bytes类型
import struct
# res = struct.pack('i',12345)
# print(res,len(res),type(res)) #长度是4 res2 = struct.pack('i',12345111)
print(res2,len(res2),type(res2)) #长度也是4 unpack_res =struct.unpack('i',res2)
print(unpack_res) #(12345111,)
# print(unpack_res[0]) #12345111
python之网络socket编程的更多相关文章
- python基础之socket编程 (转自林海峰老师)
python基础之socket编程 阅读目录 一 客户端/服务器架构 二 osi七层 三 socket层 四 socket是什么 五 套接字发展史及分类 六 套接字工作流程 七 基于TCP的套接字 ...
- Python 基础之socket编程(一)
Python 基础之socket编程(一) 可以进行通信玩儿了,感觉不错不错,网络通信就像打电话,我说一句你听一句之后,你再说一句,我听一句,就这样.....下去了.不扯淡了,来来来,看看今天都搞了点 ...
- Python 基础之socket编程(二)
Python 基础之socket编程(二) 昨天只是对socket编程做了简单的介绍,只是把socket通信的框架搭建起来,要对其中的功能进行进一步的扩充,就来看看今天的料哈! 一.基于tcp的套接字 ...
- Python 基础之socket编程(三)
python 基础之socket编程(三) 前面实现的基于socket通信只能实现什么呢?在tcp协议的通信中就是一个用户说一句,服务端给你回一句,你再给服务端说一句,服务端再给你回一句,就这样一直友 ...
- UDP协议网络Socket编程(java实现C/S通信案例)
我的博客园:https://www.cnblogs.com/chenzhenhong/p/13825286.html 我的CSDN博客:https://blog.csdn.net/Charzous/a ...
- Java:基于TCP协议网络socket编程(实现C/S通信)
目录 一.前言:TCP原理简介 二.Socket编程通信 三.TCP服务器端(具体代码) 四.TCP客户端(具体代码) 五.通信效果演示 六."创意"机器人:价值一个亿的AI核心代 ...
- java多线程实现TCP网络Socket编程(C/S通信)
目录 开篇必知必会 一.多线程技术 二.实现多线程接收 1.单线程版本 2.多线程版本 三.多线程与进程的关系 四.客户端界面完整代码 五.多线程通信对比 最后 开篇必知必会 在前一篇<Java ...
- 十三python基础之socket编程
阅读目录 一 客户端/服务器架构 二 osi七层 三 socket层 四 socket是什么 五 套接字发展史及分类 六 套接字工作流程 七 基于TCP的套接字 八 基于UDP的套接字 九 粘包现 ...
- python基础之socket编程
一 客户端/服务器架构 二 osi七层 三 socket层 四 socket是什么 五 套接字发展史及分类 六 套接字工作流程 七 基于TCP的套接字 八 基于UDP的套接字 九 粘包现象 十 什么是 ...
随机推荐
- python语言 buffer类型数据的使用 'ascii' codec can't decode byte 0xe5 问题的解决
在python中我们使用buffer类型时可以将其转换为str类型. 如果obejct的类型为<type 'buffer'> ,可以使用str(object)将其转换为字符串类型. 在转换 ...
- js基础系列框架:JS重要知识点(转载)
这里列出了一些JS重要知识点(不全面,但自己感觉很重要).彻底理解并掌握这些知识点,对于每个想要深入学习JS的朋友应该都是必须的. 讲解还是以示例代码搭配注释的形式,这里做个小目录: JS代码预解析原 ...
- UI-10-plist文件及UITableView的高级应用①
课程要点: plist文件的新建与读取 给UITableView设置变化的值 单元格的删除.插入及刷新 plist文件的新建与读取 新建plist Commadn+N,iOS->Resouce- ...
- hash和encrypt区别及应用_转
转自:哈希(Hash)与加密(Encrypt)的基本原理.区别及工程应用 0.摘要 今天看到吉日嘎拉的一篇关于管理软件中信息加密和安全的文章,感觉非常有实际意义.文中作者从实践经验出发,讨论了信息管理 ...
- linux内核常用函数或宏
1. simple_strtoul 用于将字符串转换为无符号长整数,第3个参数10意味着转换方式是10进制. ival = simple_strtoul(buffer, NULL, 10); 2. 大 ...
- 第一百九十四节,jQuery EasyUI,Droppable(放置)组件
jQuery EasyUI,Droppable(放置)组件 学习要点: 1.加载方式 2.属性列表 3.事件列表 4.方法列表 本节课重点了解 EasyUI 中 Droppable(放置)组件的使用方 ...
- nodejs rar/zip加密压缩、解压缩
1.shell/cmd命令行压缩解压缩 (1)zip压缩解压缩 zip压缩:zip -rP{密码} <目标文件.zip> <源文件> //默认覆盖现有文件 zip解压缩:zip ...
- WPF 中双向绑定通知机制之ObservableCollection使用
msdn中 ObservableCollection<T> 类 表示一个动态数据集合,在添加项.移除项或刷新整个列表时,此集合将提供通知. 在许多情况下,所使用的数据是对象的集合 ...
- C++中的return返回值:return0 or return -1?
C++98 中定义了如下两种 main 函数的定义方式: int main( ) int main( int argc, char *argv[] ) (参考资料:ISO/IEC 14882(19 ...
- FinalShell Mac OS版,Linux版安装及教程
该版本功能和windows版基本一样,但是主机检测和远程桌面功能由于兼容性问题暂时无法使用,以后会支持. 该版本功能和windows版基本一样,但是主机检测和远程桌面功能由于兼容性问题暂时无法使用,以 ...