内容概要

  • 楔子
  • 软件开发架构
  • 网络基础
  • 套接字(socket)
  • 粘包
  • socketserver模块

一. 楔子

   现在有两个python文件a.py和b.py,分别运行,这两个程序之间需要传递一个数据,要怎么做呢?

  可以创建一个文件,把a.py想要传递的内容写到文件中,然后b.py从这个文件中读取。

  但是a.py和b.py分别在不同电脑上的时候,怎么办?

  类似的机制有计算机网盘,qq等等。我们可以在我们的电脑上和别人聊天,可以在自己的电脑上向网盘中上传、下载内容。这些都是两个程序在通信。(客户端和服务端的交互)

二. 软件开发架构

  两个程序之间通讯的应用大致可以分为两种:

  第一种是应用类:qq、微信、网盘、优酷这一类是属于需要安装的桌面应用

  第二种是web类:比如百度、知乎、博客园等使用浏览器访问就可以直接使用的应用

  这些应用的本质其实都是两个程序之间的通讯。而这两个分类又对应了两个软件开发的架构~

1. C/S架构

  C/S:Client与Server,客户端和服务器端架构,这种架构也是从用户层面(物理层面)来划分的。

  这里的客户端一般泛指客户端应用程序EXE,程序需要先安装后,才能运行在用户的电脑上,对用户的电脑操作系统环境依赖较大。

2. B/S架构

  B/S即:Browser与Server,中文意思:浏览器端与服务器端架构,这种架构是从用户层面来划分的。

  Browser浏览器,其实也是一种Client客户端,只是这个客户端不需要大家去安装什么应用程序,只需在浏览器上通过HTTP请求服务器端相关的资源(网页资源),客户端Browser浏览器就能进行增删改查。

三. 网络基础

网络基础

1.OSI七层模型

七层模型_百度百科

2.socket概念

  Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式。 门面模式_百度百科

  它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

其实站在你的角度上看,socket就是一个模块。我们通过调用模块中已经实现的方法建立两个进程之间的连接和通信。
也有人将socket说成ip+port,因为ip是用来标识互联网中的一台主机的位置,而port是用来标识这台机器上的一个应用程序。
所以我们只要确立了ip和port就能找到一个应用程序,并且使用socket模块来与之通信。

站在你的角度看socket

3. 套接字(socket)发展史

  套接字起源于 20 世纪 70 年代加利福尼亚大学伯克利分校版本的 Unix,即人们所说的 BSD Unix。 因此,有时人们也把套接字称为“伯克利套接字”或“BSD 套接字”。一开始,套接字被设计用在同 一台主机上多个应用程序之间的通讯。这也被称进程间通讯,或 IPC。

  套接字有两种(或者称为有两个种族),分别是基于文件型的和基于网络型的。

socket_百度百科

基于文件类型的套接字家族

  套接字家族的名字:AF_UNIX

  unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信

基于网络类型的套接字家族

  套接字家族的名字:AF_INET

  (还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF_INET是使用最广泛的一个。

  python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我么只使用AF_INET)

4. tcp协议和udp协议

  TCP(Transmission Control Protocol)可靠的、面向连接的协议(eg:打电话)、传输效率低全双工通信(发送缓存&接收缓存)、面向字节流。使用TCP的应用:Web浏览器;电子邮件、文件传输程序。

  UDP(User Datagram Protocol)不可靠的、无连接的服务,传输效率高(发送前时延小),一对一、一对多、多对一、多对多、面向报文,尽最大努力服务,无拥塞控制。使用UDP的应用:域名系统 (DNS);视频流;IP语音(VoIP)。

四. 套接字(socket)初使用

  基于TCP协议的socket

#!/usr/bin/env python3
# _*_ coding:utf- _*_
import socket
sk = socket.socket()
sk.bind(("127.0.0.1",)) # 把IP绑定到套接字
sk.listen() # 监听链接 conn,addr = sk.accept() # 接收客户端链接 client_data = conn.recv() # 接收客户端信息
print(client_data) #打印客户端信息息 conn.send(b"haha") # 向客户端发送信息 conn.close() # 关闭这次的连接
sk.close() # 关闭服务器socket,相当于停止了服务

server

#!/usr/bin/env python3
# _*_ coding:utf- _*_
import socket sk = socket.socket() # 创建客户端套接字
sk.connect(("127.0.0.1",)) # 连接服务器
sk.send(b"Hi server, I am a client") # 向服务端发送信息
server_data = sk.recv() # 接收信息
print(server_data) # 打印服务端信息 sk.close() # 关闭客户端套接字

client

执行效果:

  服务端,正在等待客户端的连接。

#  查看tcp状态, 已经有一个在监听了。

客户端,连接服务端

[root@mongodb ~]# python client.py
server_data

五. 粘包

1. 粘包现象

import socket
sk = socket.socket()
sk.bind(("127.0.0.1",))
sk.listen() conn,_ = sk.accept()
conn.send(b"hello")
conn.send(b"lishichao")

server

import socket

sk = socket.socket()
sk.connect(("127.0.0.1",)) msg = sk.recv()
print(msg) msg2 = sk.recv()
print(msg2) sk.close()

client

执行结果:

b'hello'
b'lishichao'

以上是我们想要的两条数据,但是如果有延迟,结果就不是我们想要的了。

# 修改client端:

import time
import socket sk = socket.socket()
sk.connect(("127.0.0.1",))
time.sleep(0.1) # 延迟了0.
msg = sk.recv()
print(msg)
msg2 = sk.recv()
print(msg2) sk.close()

client

执行结果:两条数据粘到一块了。

b'hellolishichao'
b''

2. 粘包的原因

    

3.解决粘包

  问题的根源在于,接收端不知道发送端将要传送的字节流的长度,所以解决粘包的方法就是围绕,如何让发送端在发送数据前,把自己将要发送的字节流总大小让接收端知晓,然后接收端来一个死循环接收完所有数据。

    

struct模块

  该模块可以把一个类型,如数字,转成固定长度的bytes

import struct
ret = struct.pack("i",)
print(ret,len(ret))
# 执行结果: 将数字转成bytes,长度为4
# b'?B\x0f\x00' # 将bytes结果转回数字
res = struct.unpack("i",ret)[] # 取元素0
print(res)
#执行结果: 结果是元祖
# (,)

在接收端接收真正的信息之前,先接收数据的长度,然后按照长度来接收余下的数据
 利用struct模块完成了自定义协议的严谨模式

import socket
import struct
sk = socket.socket()
sk.bind(("127.0.0.1",))
sk.listen() conn,_ = sk.accept()
msg = b"hello,world,this is a very long message"
len_msg = struct.pack("i",len(msg))
conn.send(len_msg) # 先发送数据长度
conn.send(msg)
conn.send(b"eva") conn.close()
sk.close()

server

#!/usr/bin/env python3
# _*_ coding:utf- _*_
import socket
import struct
import time sk = socket.socket()
sk.connect(("127.0.0.1",)) time.sleep(0.1)
len_msg = sk.recv() # 接受数据的长度
len_msg = len_msg = struct.unpack("i",len_msg)[] # 转回实际的长度
msg = sk.recv(len_msg) # 根据实际长度,接收数据
print(msg) msg2 = sk.recv()
print(msg2)
sk.close()

client

服务端套接字函数
s.bind() 绑定(主机,端口号)到套接字
s.listen() 开始TCP监听
s.accept() 被动接受TCP客户的连接,(阻塞式)等待连接的到来 客户端套接字函数
s.connect() 主动初始化TCP服务器连接
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常 公共用途的套接字函数
s.recv() 接收TCP数据
s.send() 发送TCP数据
s.sendall() 发送TCP数据
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() 创建一个与该套接字相关的文件

socket更多方法介绍

4. 基于TCP实现的简单文件传输

#!/usr/bin/env python3
# _*_ coding:utf- _*_
import socket
import json
import os
import struct sk = socket.socket()
sk.bind(("0.0.0.0",))
sk.listen() conn,_ = sk.accept() # 下载
file_path = r"E:\python-25期周末班学习资料\day08\视频\3.网络基础.mp4"
file_name = os.path.basename(file_path)
print(file_name)
file_size = os.path.getsize(file_path)
print(file_size) file_info = {"file_name":file_name,"file_size":file_size}
info_json = json.dumps(file_info).encode("utf-8") # str.encode('utf-8') bytes
send_len = struct.pack("i",len(info_json)) conn.send(send_len) # 发送数据长度
conn.send(info_json) # 发送文件信息 # 发送文件
with open(file_path,"rb") as f:
while file_size > :
content = f.read() # 一次读取2048个字节
conn.send(content) # 发送数据
file_size -= len(content) conn.close()
sk.close()

server

#!/usr/bin/env python3
# _*_ coding:utf- _*_
import socket
import struct
import json sk = socket.socket()
sk.connect(("10.0.2.174",)) # 接收文件信息
json_len = sk.recv()
json_len = struct.unpack("i",json_len)[]
info_json = sk.recv(json_len).decode("utf-8")
info_dic = json.loads(info_json)
print(info_dic) # 接收文件
with open(info_dic["file_name"],"wb") as f:
while info_dic["file_size"] > :
content = sk.recv() # 接收数据
info_dic["file_size"] -= len(content)
f.write(content) # 写入文件 sk.close()

client

六. socketserver模块

  基于原生的socket tcp协议的server不能同时接收多个client端的请求,使用socketserver模块可以同时接受多个client请求

import socketserver
Host = "0.0.0.0"
Port = class FTPServer(socketserver.BaseRequestHandler):
def handle(self):
conn = self.request
addr = self.client_address
print(addr)
while True:
msg = conn.recv().decode("utf-8")
conn.send(b"hhhhh") # 创建一个server对象,将服务地址绑定到 0.0.0.0:
server = socketserver.ThreadingTCPServer((Host,Port),FTPServer) # 让server永远运行下去,除非强制停止程序
server.serve_forever()

server

import time
import socket
sk = socket.socket()
sk.connect(("127.0.0.1",)) while :
sk.send(b"hello")
msg = sk.recv()
print(msg)
time.sleep() sk.close()

client

七. FTP作业

 1. 软件的开发规范

  

bin ---     程序的入口
conf --- 配置信息
core --- 核心代码
db --- 存放程序数据
log --- 程序日志

目录结构

Python开发【第八篇】: 网络编程的更多相关文章

  1. iOS开发网络篇—网络编程基础

    iOS开发网络篇—网络编程基础 一.为什么要学习网络编程 1.简单说明 在移动互联网时代,移动应用的特征有: (1)几乎所有应用都需要用到网络,比如QQ.微博.网易新闻.优酷.百度地图 (2)只有通过 ...

  2. Python开发【第一篇】:目录

    本系列博文包含 Python基础.前端开发.Web框架.缓存以及队列等,希望可以给正在学习编程的童鞋提供一点帮助!!! Python开发[第一篇]:目录 Python开发[第二篇]:初识Python ...

  3. Python开发【第二篇】:初识Python

    Python开发[第二篇]:初识Python   Python简介 Python前世今生 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏 ...

  4. Python全栈【Socket网络编程】

    Python全栈[socket网络编程] 本章内容: Socket 基于TCP的套接字 基于UDP的套接字 TCP粘包 SocketServer 模块(ThreadingTCPServer源码剖析) ...

  5. python基础教程总结13——网络编程,

    1.网络设计模块 1.1 socket模块    根据连接启动的方式以及本地套接字要连接的目标,套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认. 1)服务器监听:是服务器端套接 ...

  6. Python开发【第一篇】:目录

    本系列博文包含Python基础.前端开发.Web框架.缓存以及队列等,希望可以给正在学习Python编程的朋友们提供一点帮助! .Python开发[第一篇]:目录 .Python开发[第二篇]:初始P ...

  7. 第八篇:python基础_8 面向对象与网络编程

    本篇内容 接口与归一化设计 多态与多态性 封装 面向对象高级 异常处理 网络编程 一. 接口与归一化设计 1.定义 (1)归一化让使用者无需关心对象的类是什么,只需要知道这些对象都具备某些功能就可以了 ...

  8. Python开发【第*篇】【Socket网络编程】

    1.Socket socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. so ...

  9. iOS开发网络篇—网络编程基础(一)

    一.为什么要学习网络编程 1.简单说明 在移动互联网时代,移动应用的特征有: (1)几乎所有应用都需要用到网络,比如QQ.微博.网易新闻.优酷.百度地图 (2)只有通过网络跟外界进行数据交互.数据更新 ...

  10. Python之路(第三十篇) 网络编程:socket、tcp/ip协议

    一.客户端/服务器架构 1.硬件C/S架构(打印机) 打印机作为一个服务端,电脑连接打印机进行打印 2.软件C/S架构 互联网中处处是C/S架构 如谷歌网站是服务端,你的浏览器是客户端(B/S架构也是 ...

随机推荐

  1. C# 用XiliumCefGlue做浏览器,JS和C#相互调用

    原文:C# 用XiliumCefGlue做浏览器,JS和C#相互调用 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u013564470/artic ...

  2. google 搜索结果在新标签中打开

    google->setting->search setting->Where results open->检查

  3. 搭建本地yum源和局域网yum源

    搭建本地yum源和局域网yum源 由于很多客户环境是专网,不允许连网,无法使用网上的各种yum源,来回拷贝rpm包安装麻烦,还得解决依赖问题.所以想着搭建个本地/局域网YUM源,方便安装软件. 1   ...

  4. [PHP7.0-PHP7.2]的新特性和新变更

    php7发布已经升级到7.2.里面发生了很多的变化.本文整理php7.0至php7.2的新特性和一些变化. 参考资料: http://php.net/manual/zh/migration70.new ...

  5. 最简单的IdentityServer实现——IdentityServer

    1.新建项目 新建ASP .Net Core项目IdentityServer.EasyDemo.IdentityServer,选择.net core 2.0   1   2 引用IdentitySer ...

  6. WPF 动态模拟CPU 使用率曲线图

    原文:WPF 动态模拟CPU 使用率曲线图      在工作中经常会遇到需要将一组数据绘制成曲线图的情况,最简单的方法是将数据导入Excel,然后使用绘图功能手动生成曲线图.但是如果基础数据频繁更改, ...

  7. Codejock.Xtreme.Toolkit.Pro.v15.3.1 下载 与 VS2015补丁使用方法

    Codejock.Xtreme.Toolkit.Pro.v15.3.1 下载 与 VS2015补丁使用方法 打算放在CSDN进行下载的,上传完成后发现资源分设置的1分,本打算赚点下载分的.在页面上没有 ...

  8. 创建hexo风格的markdown页面

    最近在用 nodejs 搭建一个个人博客,博客当然要有编辑文章的功能啦.个人比较偏爱 hexo 风格的 markdown 格式,所以想自己的博客也是这样的风格.尝试了几个库,发现 marked 的转换 ...

  9. Win8Metro(C#)数字图像处理--2.27图像加法运算

    原文:Win8Metro(C#)数字图像处理--2.27图像加法运算  [函数名称] 图像加法函数AddProcess(WriteableBitmap src, WriteableBitmap a ...

  10. WPF ListboxItem 双击事件 Command绑定

    <ListBox x:Name="Lb" HorizontalAlignment="Left" Height="600" Vertic ...