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. javaee 文件的复制

    package Shurushucu; import java.io.FileInputStream; import java.io.FileNotFoundException; import jav ...

  2. struts中日期处理以及文件下载

    日期处理 对于jsp提交的基本数据类型和日期格式为yyyy-MM-dd的自动转换为相应的 对于其它的日期格式需要自定义转换器 局部类型转换器 1,写转换器类(继承StrutsTypeConverter ...

  3. 洛谷P1563 玩具谜题 简单模拟

    没意义,注意方向别判错. Code: #include<cstdio> #include<cstring> using namespace std; const int max ...

  4. Spring AOP 介绍与基于接口的实现

    热烈推荐:超多IT资源,尽在798资源网 声明:转载文章,为防止丢失所以做此备份. 本文来自公众号:程序之心 原文地址:https://mp.weixin.qq.com/s/vo94gVyTss0LY ...

  5. css3实现滚动手表

    静态html: <!DOCTYPE html><html> <head> <meta charset="utf-8" /> < ...

  6. C调用java方法签名

    1.AS2.0 D:\androidMyWork\SmartCam\app\build\intermediates\classes\debug>javap -s com.admin.smartc ...

  7. RobotFrameWork+APPIUM实现对安卓APK的自动化测试----第七篇【元素定位介绍】

    http://blog.csdn.net/deadgrape/article/details/50628113 我想大家在玩自动化的时候最关心的一定是如何定位元素,因为元素定位不到后面的什么方法都实现 ...

  8. C/C++ 获取文件夹下的所有文件列表

    本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/51009608 提供一段C/C++代码示 ...

  9. HDU5976 Detachment

    /* HDU5976 Detachment http://acm.hdu.edu.cn/showproblem.php?pid=5976 数论 等差数列 * * */ #include <cst ...

  10. mobile touch 备用

    var _scrollIndex=1; function scrollPage(){ var _contentEle = $('.view-container'),_viewEle = _conten ...