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. 如何在CentOS 7中禁止IPv6(转载)

    最近,我的一位朋友问我该如何禁止IPv6.在搜索了一番之后,我找到了下面的方案.下面就是在我的CentOS 7 迷你服务器禁止IPv6的方法. 你可以用两个方法做到这个. 方法 1 编辑文件/etc/ ...

  2. GCJ 2008 Round 1A Minimum Scalar Product( 水 )

    链接:传送门 题意:给两个向量 v1 = { x1 , x2 , x3 , x4 .... } , v2 = { y1 , y2 , y3 , y4 ...... } 允许任意交换 v1 和 v2 各 ...

  3. POJ Pseudoprime numbers( Miller-Rabin素数测试 )

    链接:传送门 题意:题目给出费马小定理:Fermat's theorem states that for any prime number p and for any integer a > 1 ...

  4. 训练1-o

    给出2个N * N的矩阵M1和M2,输出2个矩阵相乘后的结果. Input 第1行:1个数N,表示矩阵的大小(2 <= N <= 100)第2 - N + 1行,每行N个数,对应M1的1行 ...

  5. [模板]Matrix Tree定理

    结论:一个图的生成树个数等于它的度数矩阵减邻接矩阵得到的矩阵(基尔霍夫矩阵)的任意一个n-1阶主子式的行列式的绝对值 证明:不会 求法:高斯消元 例题:[HEOI2013]小Z的房间 #include ...

  6. 经纬度计算两点间的距离,根据距离排序SQL

    #java的Utilspublic class DistanceUtil { // 地球平均半径 private static final double EARTH_RADIUS = 6378137; ...

  7. socket 客户端的认证

    一:使用 hashlib 进行加密验证: # server.py 服务端 import os import socket import hashlib ​ def check_conn(conn): ...

  8. C# try-catch-return

    正常执行try后才能执行finally,catch中的语句可能会影响finally的执行 使用 finally 块,可以清理在 Try 中分配的任何资源,而且,即使在 try 块中发生异常,您也可以运 ...

  9. Shell编程入门(第二版)(上)

    简单的示例Shell程序 示例1. #!/bin/bash #This is to show what a shell script looks like echo "Our first e ...

  10. POJ 1948

    这道题我记得是携程比赛上的一道. 开始时想直接设面积,但发现不可以,改设能否构成三角形.设dp[i][j][k]为前i根木棍构成边长为j和k的三角形,那么转移可以为dp[i][j][k]=dp[i-1 ...