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. 自定义View实现圆角化

    目的: 1.实现自定义ReleativeLayout圆角化 实现: 1.在res目录中新建attrs.xml文件,自定义属性如下. <?xml version="1.0" e ...

  2. mysql修改时区的几种方法(转载自https://www.cnblogs.com/shiqiangqiang/p/8393662.html)

    说明: 以下记录修改mysql时区的几种方法. 具体: 方法一:通过mysql命令行模式下动态修改 1.1 查看mysql当前时间,当前时区 select curtime(); #或select no ...

  3. Bind for 0.0.0.0:80 failed: port is already allocated.解决方案

    一句话总结就是容器占用的port还没有完全释放 查看进程,发现相关的容器并没有在运行,而 docker-proxy 却依然绑定着端口: $ docker ps 检查docker镜像 $ ps -aux ...

  4. 区分JAVA创建线程的几种方法

    1. start()和run()       通过调用Thread类的start()方法来启动一个线程,这时此线程是处于就绪状态,并没有运行.然后 通过此Thread类调用方法run()来完成其运行操 ...

  5. UVA1586 - Molar mass(紫书习题3.2)

    HJL是一个从不讽刺人的品学兼优的好孩子,她最近沉迷学习化学而不能自拔.然而计算一个分子的相对分子质量使她烦不胜烦,因此她决定请你写一个程序来帮助她计算这种麻烦的事情. 已知: ①C代表的碳元素的相对 ...

  6. linux github 添加ssh

    1.本地生成key,  xxx 是github 的账号, 执行下面命令一路下一步 ssh-keygen -t rsa -C "xxx" 2.复制下面的public key 到git ...

  7. java实现QQ空间模拟登录

    import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import j ...

  8. AMPL下载使用

    AMPL下载使用 依次执行以下操作 wget https://ampl.com/demo/amplide.linux64.tgz tar xzf amplide.linux64.tgz cd ampl ...

  9. Django模型Model的定义

    概述 Django对各种数据库提供了很好的支持,Django为这些数据库提供了统一的调用API,可以根据不同的业务需求选择不同的数据库. 模型.属性.表.字段间的关系 一个模型类在数据库中对应一张表, ...

  10. jQuery(表单选择器)