socket编程

  socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议

  Ip层的ip地址可以唯一标识主机,而TCP层协议和端口可以唯一标识主机的一个进程,这样可以利用IP地址+协议+端口号唯一标识网络中的一个进程

  socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用以实现进程在网络中通信。socket是一种“打开-读写-关闭”模式的实现,服务器和客户端各自维护一个“文件”,在建立连接打开后,可以向自己文件写入内容供对方读取或者读取对方内容,通讯结束时关闭文件。

套接字工作流程

  

  服务端先初始化socket,然后与端口绑定(bind),对端口进行接听(listen),调用accept阻塞,等待客户端连接。这时如果有个客户端初始化一个socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器的连接就建立了。客户端发送数据请求,服务器接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

from socket import *

s=socket(AF_INET,SOCK_STREAM) #创建套接字
s.bind(('127.0.0.1',8080)) #绑定IP地址和端口(0-65535)
s.listen(5)
conn,client_addr=s.accept() #链接成功后返回一个链接对象:(链接对象,客户端IP和端口)
#print(conn,client_addr) data=conn.recv(1024) #每次最大收取1024bytes
conn.send(data.upper()) conn.close() #关闭客户端套接字 s.close() #关闭服务器端套接字
服务端套接字函数
s.bind() 绑定(主机,端口号)到套接字
s.listen() 开始TCP监听
s.accept() 被动接受TCP客户的连接,(阻塞式)等待连接的到来 客户端套接字函数
s.connect() 主动初始化TCP服务器连接
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常
公共用途的套接字函数
s.recv() 接收TCP数据
s.send() 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
s.sendall() 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
s.recvfrom() 接收UDP数据
s.sendto() 发送UDP数据
s.getpeername() 连接到当前套接字的远端的地址
s.getsockname() 当前套接字的地址
s.getsockopt() 返回指定套接字的参数
s.setsockopt() 设置指定套接字的参数
s.close() 关闭套接字

面向锁的套接字方法
s.setblocking() 设置套接字的阻塞与非阻塞模式
s.settimeout() 设置阻塞套接字操作的超时时间
s.gettimeout() 得到阻塞套接字操作的超时时间 面向文件的套接字的函数
s.fileno() 套接字的文件描述符
s.makefile() 创建一个与该套接字相关的文件

基于TCP的套接字

#TCP服务端
from socket import *
s=socket(AF_INET,SOCK_STREAM)
s.bind(('127.0.0.1',8080))
s.listen(5)
while True: #建立和多个客户端链接
print('starting...')
conn,client_addr=s.accept() #阻塞情况1
print(client_addr)
while True:
try:
data=conn.recv(1024) #阻塞情况2
if not data:break #针对linux断开链接后会一直收空消息的处理
print('客户端消息',data)
conn.send(data.upper())
except ConnectionResetError: #非正常断开链接处理
break
conn.close()
#TCP客户端
from socket import *
c=socket(AF_INET,SOCK_STREAM)
c.connect(('127.0.0.1',8080))
while True:
msg=input("message:").strip()
if not msg:continue #客户端发送空消息处理
c.send(msg.encode('utf-8'))
data=c.recv(1024)
print(data)
c.close()
#模拟ssh通信
from socket import *
import subprocess
import struct server=socket(AF_INET,SOCK_STREAM)
server.bind(('127.0.0.1',8081))
server.listen(5) print('starting...')
conn,client_addr=server.accept()
print(client_addr) while True:
try:
cmd=conn.recv(8096)
if not cmd:break obj=subprocess.Popen(cmd.decode('utf-8'),shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
stdout=obj.stdout.read()
stderr=obj.stderr.read() #制作固定长度的报头
total_size=len(stdout)+len(stderr)
headers=struct.pack('i',total_size)
# 发送命令的长度
conn.send(headers) #发送命令的执行结果
conn.send(stdout)
conn.send(stderr)
except ConnectionResetError:
break conn.close()
server.close()

模拟ssh通信_服务端

#模拟ssh通信
from socket import *
import struct client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8081)) while True:
cmd=input("message:").strip()
if not cmd:continue
client.send(cmd.encode('utf-8')) #接收命令长度
headers=client.recv(4)
total_size=struct.unpack('i',headers)[0]
#接收命令结果
recv_size=0
data=b''
while recv_size < total_size:
recv_data=client.recv(1024)
data+=recv_data
recv_size+=len(recv_data) print(data.decode('gbk')) client.close()

模拟ssh通信_客户端

粘包现象及解决方案

  只有TCP有粘包现象,UDP没有。粘包问题主要是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据造成的。

#服务端
from socket import *
import time server=socket(AF_INET,SOCK_STREAM)
server.bind(('127.0.0.1',8081))
server.listen(5) print('starting...')
conn,client_addr=server.accept() res1=conn.recv(1)
print('res1:',res1) time.sleep(6)
res2=conn.recv(10)
print('res2',res2) conn.close()
server.close()
#客户端
from socket import *
import time client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8081)) client.send('hello'.encode('utf-8'))
time.sleep(5)
client.send('world'.encode('utf-8')) client.close()

  解决粘包现象

from socket import *
import subprocess
import struct
import json server=socket(AF_INET,SOCK_STREAM)
server.bind(('127.0.0.1',8081))
server.listen(5) print('starting...')
conn,client_addr=server.accept()
print(client_addr) while True:
try:
cmd=conn.recv(8096)
if not cmd:break obj=subprocess.Popen(cmd.decode('utf-8'),shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
stdout=obj.stdout.read()
stderr=obj.stderr.read() #制作固定长度的报头
headers = {
'filepath': 'a.txt',
'md5': 'fdgre343fg',
'total_size': len(stderr)+len(stdout)
} headers_json = json.dumps(headers)
headers_bytes = headers_json.encode('utf-8') #发送报头的长度
conn.send(struct.pack('i',len(headers_bytes))) # 发送报头
conn.send(headers_bytes) #发送命令的执行结果
conn.send(stdout)
conn.send(stderr)
except ConnectionResetError:
break conn.close()
server.close()

服务端

from socket import *
import struct
import json client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8081)) while True:
cmd=input("message:").strip()
if not cmd:continue
client.send(cmd.encode('utf-8')) #接收报头长度
headers_size=struct.unpack('i',client.recv(4))[0]
#接收报头
headers_bytes=client.recv(headers_size)
headers_json=headers_bytes.decode('utf-8')
headers_dic=json.loads(headers_json)
total_size=headers_dic['total_size'] #接收命令结果
recv_size=0
data=b''
while recv_size < total_size:
recv_data=client.recv(1024)
data+=recv_data
recv_size+=len(recv_data) print(data.decode('gbk')) client.close()

客户端

第十二章 Python网络编程的更多相关文章

  1. 疯狂JAVA讲义---第十二章:Swing编程(五)进度条和滑动条

    http://blog.csdn.net/terryzero/article/details/3797782 疯狂JAVA讲义---第十二章:Swing编程(五)进度条和滑动条 标签: swing编程 ...

  2. 第十二章 Python文件操作【转】

    12.1 open() open()函数作用是打开文件,返回一个文件对象. 用法格式:open(name[, mode[, buffering[,encoding]]]) -> file obj ...

  3. 十二、java_网络编程

    目录: 一.网络基础 二.TCP/IP协议 三.IP地址 四.Socket通信 一.网络基础 什么是计算机网络: 把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大.功能强的网络系 ...

  4. 第十二章 Python标准库内置模块和包简介

    在<第十章 Python的模块和包>老猿详细介绍了Python模块和包的相关概念,模块和包是Python功能扩展的重要手段,也是Python开放的重要特征.为了提供强大的能力,Python ...

  5. [CSAPP笔记][第十二章并发编程]

    第十二章 并发编程 如果逻辑控制流在时间上是重叠,那么它们就是并发的(concurrent).这种常见的现象称为并发(concurrency). 硬件异常处理程序,进程和Unix信号处理程序都是大家熟 ...

  6. python 教程 第二十二章、 其它应用

    第二十二章. 其它应用 1)    Web服务 ##代码 s 000063.SZ ##开盘 o 26.60 ##最高 h 27.05 ##最低 g 26.52 ##最新 l1 26.66 ##涨跌 c ...

  7. Python 网络编程(二)

    Python 网络编程 上一篇博客介绍了socket的基本概念以及实现了简单的TCP和UDP的客户端.服务器程序,本篇博客主要对socket编程进行更深入的讲解 一.简化版ssh实现 这是一个极其简单 ...

  8. 《Linux命令行与shell脚本编程大全》 第二十二章 学习笔记

    第二十二章:使用其他shell 什么是dash shell Debian的dash shell是ash shell的直系后代,ash shell是Unix系统上原来地Bourne shell的简化版本 ...

  9. JavaScript DOM编程艺术-学习笔记(第十二章)

    第十二章 1.本章是综合前面章节的所有东西的,一个综合实例 2.流程:①项目简介:a.获取原始资料(包括文本.图片.音视频等) b.站点结构(文件目录结构) c.页面(文件)结构 ②设计(切图) ③c ...

随机推荐

  1. Java中数组的反转

    public class ArrayDemo2 { public static void main(String[] args) { //定义一个数组存放元素 int[] arr3 = {10, 20 ...

  2. IE 11 浏览器兼容性视图设置

    1.打开IE 浏览器. 2.选择“工具”---“兼容性视图设置”.3.在“在兼容性视图中显示所有网站”前面勾选住. 点击关闭就可以了. 开发人员工具 1.找到“工具”----“F12开发人员工具”.2 ...

  3. Python可视化数据------seaborn

    可以看链接:https://blog.csdn.net/unixtch/article/details/78820654 1.import seaborn as sns 2.seaborn的主题风格( ...

  4. NGUI学习随笔

    一.NGUI的直接用法 1.      Attach a Collider:表示为NGUI的某些物体添加碰撞器,如果界面是用NGUI做的,只能这样添加.(注:用Component添加无效). 2.  ...

  5. JavaScript进阶【一】JavaScript模块化开发的基础知识

    //模块化的最初写法 //1.最初写法 //下面的m1和m2就组成了一个模块 //缺点:"污染"了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间看不出直接关系. f ...

  6. 驱动中的IO访问

    1,内存空间与IO空间 1)I/O 映射方式(I/O-mapped) 典型地,如X86处理器为外设专门实现了一个单独的地址空间,称为"I/O地址空间"或者"I/O端口空间 ...

  7. LaTeX 加粗

    本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/50997822 LaTeX中文本加粗的方 ...

  8. LaTeX soul包

    本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/50774955 详细的soul包的官方P ...

  9. BLOB的读写操作

    //BLOB写入操作package zxt.xsfw.action.ceshi; import javax.servlet.http.HttpServletRequest; import javax. ...

  10. Linux Unix shell 编程指南学习笔记(第三部分)

    第十三章  登陆环境 登陆系统时.输入username和password后.假设验证通过.则进入登录环境. 登录过程 文件/etc/passwd $HOME.profile 定制$HOME.profi ...