day8-异常处理与网络编程

 

第1章 异常处理

1.1 什么是异常?

1.1.1 描述

#1 什么是异常?

# 异常是错误发生的信号,一旦程序出错,就会产生一个异常,应用程序未处理该异常,

# 异常便会抛出,程序随之终止

 

异常就是程序运行时发生错误的信号(在程序出现错误时,则会产生一个异常,若程序没有处理它,则会抛出该异常,程序的运行也随之终止),在python中,错误触发的异常如下

 

1.1.2 错误分类

而错误分成两种

1.语法错误(这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正)

#语法错误示范一

if

#语法错误示范二

def test:

    pass

#语法错误示范三

class Foo

    pass

#语法错误示范四

print(haha
语法错误
2.逻辑错误

#TypeError:int类型不可迭代

for i in 3:

    pass

#ValueError

num=input(">>: ") #输入hello

int(num)

 

#NameError

aaa

 

#IndexError

l=['egon','aa']

l[3]

 

#KeyError

dic={'name':'egon'}

dic['age']

 

#AttributeError

class Foo:pass

Foo.x

 

#ZeroDivisionError:无法完成计算

res1=1/0

res2=1+'str'
逻辑错误

1.2 异常的种类

在python中不同的异常可以用不同的类型(python中统一了类与类型,类型即类)去标识,一个异常标识一种错误

1.2.1 常用异常

#######################常用异常####################

AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x

IOError 输入/输出异常;基本上是无法打开文件

ImportError 无法引入模块或包;基本上是路径问题或名称错误

IndentationError 语法错误(的子类) ;代码没有正确对齐

IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]

KeyError 试图访问字典里不存在的键

KeyboardInterrupt Ctrl+C被按下

NameError 使用一个还未被赋予对象的变量

SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)

TypeError 传入对象类型与要求的不符合

UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,

导致你以为正在访问它

ValueError 传入一个调用者不期望的值,即使值的类型是正确的

 

 
常用异常

1.2.2 更多异常

ArithmeticError

AssertionError

AttributeError

BaseException

BufferError

BytesWarning

DeprecationWarning

EnvironmentError

EOFError

Exception

FloatingPointError

FutureWarning

GeneratorExit

ImportError

ImportWarning

IndentationError

IndexError

IOError

KeyboardInterrupt

KeyError

LookupError

MemoryError

NameError

NotImplementedError

OSError

OverflowError

PendingDeprecationWarning

ReferenceError

RuntimeError

RuntimeWarning

StandardError

StopIteration

SyntaxError

SyntaxWarning

SystemError

SystemExit

TabError

TypeError

UnboundLocalError

UnicodeDecodeError

UnicodeEncodeError

UnicodeError

UnicodeTranslateError

UnicodeWarning

UserWarning

ValueError

Warning

ZeroDivisionError

 

 
更多异常

1.2.3 常见异常类型

#2、常见异常类型

#I:语法错误应该在程序运行前修正

# if 1 >2

#     print('xxxxx')

 

#II:逻辑错误

# x

 

# l=[]

# l[10000] #IndexError

 

# class Foo:

#     pass

# Foo.x #AttributeError:

 

# k={'x':1}

# k['y'] #KeyError

 

# 1/0 #ZeroDivisionError

 

# for i in 3: #TypeError:

#     pass

 

 

# age=input('>>: ') #ValueError

# age=int(age)

 
常见异常类型

1.3 异常处理

1.3.1 异常处理描述

为了保证程序的健壮性与容错性,即在遇到错误时程序不会崩溃,我们需要对异常进行处理,

如果错误发生的条件是可预知的,我们需要用if进行处理:在错误发生之前进行预防

AGE=10

while True:

    age=input('>>: ').strip()

    if age.isdigit(): #只有在age为字符串形式的整数时,下列代码才不会出错,该条件是可预知的

        age=int(age)

        if age == AGE:

            print('you got it')

            break

 
View Code

如果错误发生的条件是不可预知的,则需要用到try...except:在错误发生之后进行处理

#基本语法为

try:

    被检测的代码块

except 异常类型:

    try中一旦检测到异常,就执行这个位置的逻辑

#举例

try:

    f=open('a.txt')

    g=(line.strip() for line in f)

    print(next(g))

    print(next(g))

    print(next(g))

    print(next(g))

    print(next(g))

except StopIteration:

    f.close()
View Code

1.3.2 异常分类使用

#1 异常类只能用来处理指定的异常情况,如果非指定异常则无法处理。

s1 = 'hello'

try:

    int(s1)

except IndexError as e: # 未捕获到异常,程序直接报错

    print e

 

#2 多分支

s1 = 'hello'

try:

    int(s1)

except IndexError as e:

    print(e)

except KeyError as e:

    print(e)

except ValueError as e:

    print(e)

 

#3 万能异常Exception

s1 = 'hello'

try:

    int(s1)

except Exception as e:

    print(e)

 

#4 多分支异常与万能异常

#4.1 如果你想要的效果是,无论出现什么异常,我们统一丢弃,或者使用同一段代码逻辑去处理他们,那么骚年,大胆的去做吧,只有一个Exception就足够了。

#4.2 如果你想要的效果是,对于不同的异常我们需要定制不同的处理逻辑,那就需要用到多分支了。

 

#5 也可以在多分支后来一个Exception

s1 = 'hello'

try:

    int(s1)

except IndexError as e:

    print(e)

except KeyError as e:

    print(e)

except ValueError as e:

    print(e)

except Exception as e:

    print(e)

 

#6 异常的其他机构

s1 = 'hello'

try:

    int(s1)

except IndexError as e:

    print(e)

except KeyError as e:

    print(e)

except ValueError as e:

    print(e)

#except Exception as e:

#    print(e)

else:

    print('try内代码块没有异常则执行我')

finally:

    print('无论异常与否,都会执行该模块,通常是进行清理工作')

 

#7 主动触发异常

try:

    raise TypeError('类型错误')

except Exception as e:

    print(e)

 

#8 自定义异常

class EgonException(BaseException):

    def __init__(self,msg):

        self.msg=msg

    def __str__(self):

        return self.msg

 

try:

    raise EgonException('类型错误')

except EgonException as e:

    print(e)

 

#9 断言:assert 条件

assert 1 == 1 

assert 1 == 2

 

#10 总结try..except

 

1:把错误处理和真正的工作分开来

2:代码更易组织,更清晰,复杂的工作任务更容易实现;

3:毫无疑问,更安全了,不至于由于一些小的疏忽而使程序意外崩溃了;

 

 
异常分类使用

1.3.3 如何处理异常实例

#3、如何处理异常

# print('====>start<=====')

#

# try:

#     l=[]

#     print(l[1111])

#     print('====>1')

#     print('====>2')

#     print('====>3')

# except IndexError:

#     pass

#

# print('====>end<=======')

 

 

 

# print('====>start<=====')

# try:

#     l=[]

#     print(l[1111])

#     print('====>1')

#     print('====>2')

#     print('====>3')

# except IndexError as e:

#     print('===>',e)

#

# print('====>end<=======')

 

 

 

 

# print('====>start<=====')

# try:

#     l=[]

#     # print(l[1111])

#     print('====>1')

#     d={}

#     d['k']

#     print('====>2')

#     print('====>3')

# except IndexError as e:

#     print('===>',e)

# except KeyError as e:

#     print('----',e)

#

# print('====>end<=======')

 

 

 

# print('====>start<=====')

# try:

#     l=[]

#     # print(l[1111])

#     print('====>1')

#     d={}

#     d['k']

#     print('====>2')

#     print('====>3')

# except IndexError:

#     pass

# except KeyError:

#     pass

# except Exception as e:

#     print('万能异常--->',e)

#

# print('====>end<=======')

 

 

 

# print('====>start<=====')

# try:

#     l=[]

#     print(l[1111])

#     # print('====>1')

#     d={}

#     # d['k']

#     # print('====>2')

#     # print('====>3')

# except IndexError:

#     pass

# except KeyError:

#     pass

# except Exception as e:

#     print('万能异常--->',e)

# else:

#     print('没有异常发生的时候触发')

# finally:

#     print('有没有异常都触发')

#

#

# print('====>end<=======')

 

 

 

'''

try:

    conn=connect('1.1.1.1',3306)

    conn.execute('select * from db1.t1')

finally:

    conn.close()

'''

 

# stus=['egon','alex','wxxx']

ip_list=[

    # '1.1.1.1:8080',

    # '1.1.1.2:8081',

    # '1.1.1.3:8082',

]

 

# if len(ip_list) == 0:

#     raise TypeError

# assert len(ip_list) > 0

 

# print('从ip_list取出ip地址,验证可用性')

 

 

 

# class MyException(BaseException):

#     def __init__(self,msg):

#         super(MyException,self).__init__()

#         self.msg=msg

#

#     def __str__(self):

#         return '<%s>' %self.msg

#

# raise MyException('类型错误') #异常的值:print(obj)

 

 

 

 

age=input('>>: ')

if age.isdigit():

    age=int(age)

 

    if age > 50:

        print('====>too big')

 

 
如何处理异常实例

1.4 什么时候用异常处理

有的同学会这么想,学完了异常处理后,好强大,我要为我的每一段程序都加上try...except,干毛线去思考它会不会有逻辑错误啊,这样就很好啊,多省脑细胞===》2B青年欢乐多

首先try...except是你附加给你的程序的一种异常处理的逻辑,与你的主要的工作是没有关系的,这种东西加的多了,会导致你的代码可读性变差

然后异常处理本就不是你2b逻辑的擦屁股纸,只有在错误发生的条件无法预知的情况下,才应该加上try...except,其他的逻辑错误应该尽量修正。

 

第2章 网络编程

2.1 楔子

你现在已经学会了写python代码,假如你写了两个python文件a.py和b.py,分别去运行,你就会发现,这两个python的文件分别运行的很好。但是如果这两个程序之间想要传递一个数据,你要怎么做呢?

这个问题以你现在的知识就可以解决了,我们可以创建一个文件,把a.py想要传递的内容写到文件中,然后b.py从这个文件中读取内容就可以了。

 

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

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

 

2.2 软件开发的架构

我们了解的涉及到两个程序之间通讯的应用大致可以分为两种:

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

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

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

2.2.1 C/S架构

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

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

 

2.2.2 B/S架构

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

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

 

 

2.3 网络基础

2.3.1 详细请见外链地址

http://www.cnblogs.com/Eva-J/articles/8066842.html

或者

http://www.cnblogs.com/linhaifeng/articles/5937962.html

 

2.3.2 一个程序如何在网络上找到另一个程序?

首先,程序必须要启动,其次,必须有这台机器的地址,我们都知道我们人的地址大概就是国家\省\市\区\街道\楼\门牌号这样字。那么每一台联网的机器在网络上也有自己的地址,它的地址是怎么表示的呢?

就是使用一串数字来表示的,例如:100.4.5.6

#########################什么是ip地址?############################

IP地址是指互联网协议地址(英语:Internet Protocol Address,又译为网际协议地址),是IP Address的缩写。IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。
IP地址是一个32位的二进制数,通常被分割为4个“8位二进制数”(也就是4个字节)。IP地址通常用“点分十进制”表示成(a.b.c.d)的形式,其中,a,b,c,d都是0~255之间的十进制整数。例:点分十进IP地址(100.4.5.6),实际上是32位二进制数(01100100.00000100.00000101.00000110)。
#####################什么是端口#########################

"端口"是英文port的意译,可以认为是设备与外界通讯交流的出口。

因此ip地址精确到具体的一台电脑,而端口精确到具体的程序。

2.4 osi七层模型

2.4.1 引子

须知一个完整的计算机系统是由硬件、操作系统、应用软件三者组成,具备了这三个条件,一台计算机系统就可以自己跟自己玩了(打个单机游戏,玩个扫雷啥的)

如果你要跟别人一起玩,那你就需要上网了,什么是互联网?

互联网的核心就是由一堆协议组成,协议就是标准,比如全世界人通信的标准是英语,如果把计算机比作人,互联网协议就是计算机界的英语。所有的计算机都学会了互联网协议,那所有的计算机都就可以按照统一的标准去收发信息从而完成通信了。

 

2.4.2 osi七层模型

人们按照分工不同把互联网协议从逻辑上划分了层级:

 

2.4.3 为何学习socket一定要先学习互联网协议

为何学习socket一定要先学习互联网协议:

1.首先:本节课程的目标就是教会你如何基于socket编程,来开发一款自己的C/S架构软件

2.其次:C/S架构的软件(软件属于应用层)是基于网络进行通信的

3.然后:网络的核心即一堆协议,协议即标准,你想开发一款基于网络通信的软件,就必须遵循这些标准。

4.最后:就让我们从这些标准开始研究,开启我们的socket编程之旅

 

2.5 socket概念

2.5.1 socket层

 

2.5.2 理解socket

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

###################站在你的角度上看socket########################

其实站在你的角度上看,socket就是一个模块。我们通过调用模块中已经实现的方法建立两个进程之间的连接和通信。

也有人将socket说成ip+port,因为ip是用来标识互联网中的一台主机的位置,而port是用来标识这台机器上的一个应用程序。

所以我们只要确立了ip和port就能找到一个应用程序,并且使用socket模块来与之通信。

2.6 套接字(socket)的发展史

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

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

套接字家族的名字:AF_UNIX

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

 

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

套接字家族的名字:AF_INET

(还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我么只使用AF_INET)

 

2.7 套接字工作流程

  一个生活中的场景。你要打电话给一个朋友,先拨号,朋友听到电话铃声后提起电话,这时你和你的朋友就建立起了连接,就可以讲话了。等交流结束,挂断电话结束此次交谈。 生活中的场景就解释了这工作原理。

 

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

 

2.7.1 socket()模块函数用法

import socket

socket.socket(socket_family,socket_type,protocal=0)

socket_family 可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。protocol 一般不填,默认值为 0。

 

获取tcp/ip套接字

tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

 

获取udp/ip套接字

udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

 

由于 socket 模块中有太多的属性。我们在这里破例使用了'from module import *'语句。使用 'from socket import *',我们就把 socket 模块里的所有属性都带到我们的命名空间里了,这样能 大幅减短我们的代码。

例如tcpSock = socket(AF_INET, SOCK_STREAM)
socket()模块函数用法 

2.7.2 服务端套接字函数

s.bind()    绑定(主机,端口号)到套接字

s.listen()  开始TCP监听

s.accept()  被动接受TCP客户的连接,(阻塞式)等待连接的到来

 

2.7.3 客户端套接字函数

s.connect()     主动初始化TCP服务器连接

s.connect_ex()  connect()函数的扩展版本,出错时返回出错码,而不是抛出异常

 

2.7.4 公共用途的套接字函数

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()           关闭套接字

 

2.7.5 面向锁的套接字方法

s.setblocking()     设置套接字的阻塞与非阻塞模式

s.settimeout()      设置阻塞套接字操作的超时时间

s.gettimeout()      得到阻塞套接字操作的超时时间

 

2.7.6 面向文件的套接字的函数

s.fileno()          套接字的文件描述符

s.makefile()        创建一个与该套接字相关的文件

 

2.7.7 socket实验推演流程

1:用打电话的流程快速描述socket通信

2:服务端和客户端加上基于一次链接的循环通信

3:客户端发送空,卡主,证明是从哪个位置卡的

服务端:

from socket import *

phone=socket(AF_INET,SOCK_STREAM)

phone.bind(('127.0.0.1',8081))

phone.listen(5)

 

conn,addr=phone.accept()

while True:

    data=conn.recv(1024)

    print('server===>')

    print(data)

    conn.send(data.upper())

conn.close()

phone.close()

客户端:

from socket import *

 

phone=socket(AF_INET,SOCK_STREAM)

phone.connect(('127.0.0.1',8081))

 

while True:

    msg=input('>>: ').strip()

    phone.send(msg.encode('utf-8'))

    print('client====>')

    data=phone.recv(1024)

    print(data)

 

说明卡的原因:缓冲区为空recv就卡住,引出原理图

 

 

 

4.演示客户端断开链接,服务端的情况,提供解决方法

 

5.演示服务端不能重复接受链接,而服务器都是正常运行不断来接受客户链接的

 

6:简单演示udp

服务端

from socket import *

phone=socket(AF_INET,SOCK_DGRAM)

phone.bind(('127.0.0.1',8082))

while True:

    msg,addr=phone.recvfrom(1024)

    phone.sendto(msg.upper(),addr)

客户端

from socket import *

phone=socket(AF_INET,SOCK_DGRAM)

while True:

    msg=input('>>: ')

    phone.sendto(msg.encode('utf-8'),('127.0.0.1',8082))

    msg,addr=phone.recvfrom(1024)

    print(msg)

 

udp客户端可以并发演示

udp客户端可以输入为空演示,说出recvfrom与recv的区别,暂且不提tcp流和udp报的概念,留到粘包去说

 

 
socket实验推演流程

2.8 基于TCP的套接字

tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端

2.8.1 实例一server端与client端

#################server端#################

import socket

sk = socket.socket()

sk.bind(('127.0.0.1',8898))  #把地址绑定到套接字

sk.listen()          #监听链接

conn,addr = sk.accept() #接受客户端链接

ret = conn.recv(1024)  #接收客户端信息

print(ret)       #打印客户端信息

conn.send(b'hi')        #向客户端发送信息

conn.close()       #关闭客户端套接字

sk.close()        #关闭服务器套接字(可选)
server端
#####################client端############################

import socket

sk = socket.socket()           # 创建客户套接字

sk.connect(('127.0.0.1',8898))    # 尝试连接服务器

sk.send(b'hello!')

ret = sk.recv(1024)         # 对话(发送/接收)

print(ret)

sk.close()            # 关闭客户套接字

 
client端

2.8.2 问题:有的同学在重启服务端时可能会遇到

 

##################解决方法###################

#加入一条socket配置,重用ip和端口

import socket

from socket import SOL_SOCKET,SO_REUSEADDR

sk = socket.socket()

sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加

sk.bind(('127.0.0.1',8898))  #把地址绑定到套接字

sk.listen()          #监听链接

conn,addr = sk.accept() #接受客户端链接

ret = conn.recv(1024)   #接收客户端信息

print(ret)              #打印客户端信息

conn.send(b'hi')        #向客户端发送信息

conn.close()       #关闭客户端套接字

sk.close()        #关闭服务器套接字(可选)
解决方法

2.8.3 实例二server端与client端

##################server端######################

import socket

 

#1、买手机

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #tcp协议

 

#2、绑定手机

# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

phone.bind(('127.0.0.1',8081)) #0-65535

 

#3、开机

phone.listen(5)

 

#4、等待电话连接

print('starting...')

conn,client_addr=phone.accept() #(conn,client_addr)

print(conn,client_addr)

 

#5、收\发消息

data=conn.recv(1024) #1024bytes?

 

conn.send(data.upper())

 

#6、挂电话连接

conn.close()

 

#7、关机

phone.close()

 

 
server端
################client端####################

import socket

 

#1、买手机

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #tcp协议

 

#2、拨电话

phone.connect(('127.0.0.1',8081)) #0-65535

 

#3、发收消息

phone.send('hello'.encode('utf-8'))

 

data=phone.recv(1024)

print(data)

 

#4、挂电话

phone.close()

 
client端

2.8.4 实例二加上链接循环与通信循环进阶版

模拟一个服务端三个客户端连接通信

#######################服务端进阶版###########################

import socket

 

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #tcp协议

# print(phone)

# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

phone.bind(('127.0.0.1',8083)) #0-65535

phone.listen(5)

 

print('starting...')

while True: #链接循环

    conn,client_addr=phone.accept() #(conn,client_addr)

    # print(conn,client_addr)

    print(client_addr)

 

    while True: #通信循环

        try:

            data=conn.recv(1024) #1024bytes?

            if not data:break #针对的是linux系统

            print('客户端消息',data)

            conn.send(data.upper())

            # print('====has send')

        except ConnectionResetError:

            break

    conn.close()

 

phone.close()

 

 
服务端进阶版
#############client端一进阶版#####################

import socket

 

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #tcp协议

phone.connect(('127.0.0.1',8083)) #0-65535

 

while True:

    msg=input('>>: ') #msg=' '

    if not msg:continue

 

    phone.send(msg.encode('utf-8'))

    # print('has send===>')

    data=phone.recv(1024)

    # print('has recv===>')

    print(data)

 

phone.close()

 
client端一进阶版
#############client端二进阶版#####################

import socket

 

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #tcp协议

phone.connect(('127.0.0.1',8083)) #0-65535

 

while True:

    msg=input('>>: ').strip()

    if not msg:continue

 

    phone.send(msg.encode('utf-8'))

    # print('has send===>')

    data=phone.recv(1024)

    # print('has recv===>')

    print(data)

 

phone.close()

 

 
client端二进阶版
#############client端三进阶版#####################

import socket

 

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #tcp协议

phone.connect(('127.0.0.1',8083)) #0-65535

 

while True:

    msg=input('>>: ').strip()

    if not msg:continue

 

    phone.send(msg.encode('utf-8'))

    # print('has send===>')

    data=phone.recv(1024)

    # print('has recv===>')

    print(data)

 

phone.close()

 
client端三进阶版

2.8.5 实现ssh远程执行命令

#################服务端##################

from socket import *

import subprocess

 

server=socket(AF_INET,SOCK_STREAM)

server.bind(('127.0.0.1',8090))

server.listen(5)

 

while True:

    conn,client_addr=server.accept()

    print(client_addr)

 

    while True:

        try:

            cmd=conn.recv(1024)

            if not cmd:break

 

            #ls -l;sadfasdf;pwd;echo 123

            obj=subprocess.Popen(cmd.decode('utf-8'),shell=True,

                             stdout=subprocess.PIPE,

                             stderr=subprocess.PIPE

                             )

            stdout=obj.stdout.read()

            stderr=obj.stderr.read()

 

            cmd_res=stdout+stderr

            print(len(cmd_res))

            conn.send(cmd_res)

        except ConnectionResetError:

            break

    conn.close()

 

server.close()

 
服务端
#####################client端#################

from socket import *

 

client=socket(AF_INET,SOCK_STREAM)

client.connect(('127.0.0.1',8090))

 

while True:

    cmd=input('>>: ').strip()

    if not cmd:continue

    client.send(cmd.encode('utf-8'))

    data=client.recv(1024)

    print(data.decode('gbk'))

 

client.close()
client端

2.9 基于UDP协议的socket

udp是无链接的,先启动哪一端都不会报错

2.9.1 简单使用

###################server端#####################

import socket

udp_sk = socket.socket(type=socket.SOCK_DGRAM)   #创建一个服务器的套接字

udp_sk.bind(('127.0.0.1',9000))        #绑定服务器套接字

msg,addr = udp_sk.recvfrom(1024)

print(msg)

udp_sk.sendto(b'hi',addr)                 # 对话(接收与发送)

udp_sk.close()                         # 关闭服务器套接字
server端
#######################client端#######################

import socket

ip_port=('127.0.0.1',9000)

udp_sk=socket.socket(type=socket.SOCK_DGRAM)

udp_sk.sendto(b'hello',ip_port)

back_msg,addr=udp_sk.recvfrom(1024)

print(back_msg.decode('utf-8'),addr)
client端

2.9.2 qq聊天

#################server端#############################

#_*_coding:utf-8_*_

import socket

ip_port=('127.0.0.1',8081)

udp_server_sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

udp_server_sock.bind(ip_port)

 

while True:

    qq_msg,addr=udp_server_sock.recvfrom(1024)

    print('来自[%s:%s]的一条消息:\033[1;44m%s\033[0m' %(addr[0],addr[1],qq_msg.decode('utf-8')))

    back_msg=input('回复消息: ').strip()

 

    udp_server_sock.sendto(back_msg.encode('utf-8'),addr)
server端
##################################client端#####################

#_*_coding:utf-8_*_

import socket

BUFSIZE=1024

udp_client_socket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

 

qq_name_dic={

    '金老板':('127.0.0.1',8081),

    '哪吒':('127.0.0.1',8081),

    'egg':('127.0.0.1',8081),

    'yuan':('127.0.0.1',8081),

}

 

 

while True:

    qq_name=input('请选择聊天对象: ').strip()

    while True:

        msg=input('请输入消息,回车发送,输入q结束和他的聊天: ').strip()

        if msg == 'q':break

        if not msg or not qq_name or qq_name not in qq_name_dic:continue

        udp_client_socket.sendto(msg.encode('utf-8'),qq_name_dic[qq_name])

 

        back_msg,addr=udp_client_socket.recvfrom(BUFSIZE)

        print('来自[%s:%s]的一条消息:\033[1;44m%s\033[0m' %(addr[0],addr[1],back_msg.decode('utf-8')))

 

udp_client_socket.close()

 
client端

2.9.3 时间服务器

#################server端#############################

# _*_coding:utf-8_*_

from socket import *

from time import strftime

 

ip_port = ('127.0.0.1', 9000)

bufsize = 1024

 

tcp_server = socket(AF_INET, SOCK_DGRAM)

tcp_server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)

tcp_server.bind(ip_port)

 

while True:

    msg, addr = tcp_server.recvfrom(bufsize)

    print('===>', msg)

 

    if not msg:

        time_fmt = '%Y-%m-%d %X'

    else:

        time_fmt = msg.decode('utf-8')

    back_msg = strftime(time_fmt)

 

    tcp_server.sendto(back_msg.encode('utf-8'), addr)

 

tcp_server.close()
server端
#################client端#############################

#_*_coding:utf-8_*_

from socket import *

ip_port=('127.0.0.1',9000)

bufsize=1024

 

tcp_client=socket(AF_INET,SOCK_DGRAM)

 

 

 

while True:

    msg=input('请输入时间格式(例%Y %m %d)>>: ').strip()

    tcp_client.sendto(msg.encode('utf-8'),ip_port)

 

    data=tcp_client.recv(bufsize)
client端

2.10 socket参数的详解

socket.socket(family=AF_INET,type=SOCK_STREAM,proto=0,fileno=None)

创建socket对象的参数说明:

family

地址系列应为AF_INET(默认值),AF_INET6,AF_UNIX,AF_CAN或AF_RDS。
(AF_UNIX 域实际上是使用本地 socket 文件来通信)

type

套接字类型应为SOCK_STREAM(默认值),SOCK_DGRAM,SOCK_RAW或其他SOCK_常量之一。
SOCK_STREAM 是基于TCP的,有保障的(即能保证数据正确传送到对方)面向连接的SOCKET,多用于资料传送。 
SOCK_DGRAM 是基于UDP的,无保障的面向消息的socket,多用于在网络上发广播信息。

proto

协议号通常为零,可以省略,或者在地址族为AF_CAN的情况下,协议应为CAN_RAW或CAN_BCM之一。

fileno

如果指定了fileno,则其他参数将被忽略,导致带有指定文件描述符的套接字返回。
与socket.fromfd()不同,fileno将返回相同的套接字,而不是重复的。
这可能有助于使用socket.close()关闭一个独立的插座。

 

2.11 粘包

2.11.1 黏包现象

让我们基于tcp先制作一个远程执行命令的程序(命令ls -l ; lllllll ; pwd)

###########################注意#########################

res=subprocess.Popen(cmd.decode('utf-8'),

shell=True,

stderr=subprocess.PIPE,

stdout=subprocess.PIPE)

 

的结果的编码是以当前所在的系统为准的,如果是windows,那么res.stdout.read()读出的就是GBK编码的,在接收端需要用GBK解码
且只能从管道里读一次结果

同时执行多条命令之后,得到的结果很可能只有一部分,在执行其他命令的时候又接收到之前执行的另外一部分结果,这种显现就是黏包。

2.11.2 基于tcp协议实现的黏包

########################tcp - server###################

#_*_coding:utf-8_*_

from socket import *

import subprocess

 

ip_port=('127.0.0.1',8888)

BUFSIZE=1024

 

tcp_socket_server=socket(AF_INET,SOCK_STREAM)

tcp_socket_server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)

tcp_socket_server.bind(ip_port)

tcp_socket_server.listen(5)

 

while True:

    conn,addr=tcp_socket_server.accept()

    print('客户端',addr)

 

    while True:

        cmd=conn.recv(BUFSIZE)

        if len(cmd) == 0:break

 

        res=subprocess.Popen(cmd.decode('utf-8'),shell=True,

                         stdout=subprocess.PIPE,

                         stdin=subprocess.PIPE,

                         stderr=subprocess.PIPE)

 

        stderr=res.stderr.read()

        stdout=res.stdout.read()

        conn.send(stderr)

        conn.send(stdout)

 
tcp - server
######################tcp - client#######################

#_*_coding:utf-8_*_

import socket

BUFSIZE=1024

ip_port=('127.0.0.1',8888)

 

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

res=s.connect_ex(ip_port)

 

while True:

    msg=input('>>: ').strip()

    if len(msg) == 0:continue

    if msg == 'quit':break

 

    s.send(msg.encode('utf-8'))

    act_res=s.recv(BUFSIZE)

 

    print(act_res.decode('utf-8'),end='')
tcp - client

2.11.3 基于tcp协议黏包现象实例二

#################server端###################

from socket import *

import time

 

server=socket(AF_INET,SOCK_STREAM)

server.bind(('127.0.0.1',8091))

server.listen(5)

 

conn,addr=server.accept()

 

#b'hello'

res1=conn.recv(5) #b'h'

print('res1: ',res1)

 

# b'elloworld'

time.sleep(6)

res2=conn.recv(5)

print('res2: ',res2)

 

conn.close()

server.close()

 

 
server端
######################client端##############################

from socket import *

import time

 

client=socket(AF_INET,SOCK_STREAM)

client.connect(('127.0.0.1',8091))

 

client.send('hello'.encode('utf-8')) #b'hello'

time.sleep(5)

client.send('world'.encode('utf-8')) #b'world'

 

client.close()
client端

2.11.4 基于udp协议实现的黏包

#################udp - server######################

#_*_coding:utf-8_*_

from socket import *

import subprocess

 

ip_port=('127.0.0.1',9000)

bufsize=1024

 

udp_server=socket(AF_INET,SOCK_DGRAM)

udp_server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)

udp_server.bind(ip_port)

 

while True:

    #收消息

    cmd,addr=udp_server.recvfrom(bufsize)

    print('用户命令----->',cmd)

 

    #逻辑处理

    res=subprocess.Popen(cmd.decode('utf-8'),shell=True,stderr=subprocess.PIPE,stdin=subprocess.PIPE,stdout=subprocess.PIPE)

    stderr=res.stderr.read()

    stdout=res.stdout.read()

 

    #发消息

    udp_server.sendto(stderr,addr)

    udp_server.sendto(stdout,addr)

udp_server.close()

 

 
udp - server
######################udp - client#############################

from socket import *

ip_port=('127.0.0.1',9000)

bufsize=1024

 

udp_client=socket(AF_INET,SOCK_DGRAM)

 

 

while True:

    msg=input('>>: ').strip()

    udp_client.sendto(msg.encode('utf-8'),ip_port)

    err,addr=udp_client.recvfrom(bufsize)

    out,addr=udp_client.recvfrom(bufsize)

    if err:

        print('error : %s'%err.decode('utf-8'),end='')

    if out:

        print(out.decode('utf-8'), end='')
udp - client

注意:只有TCP有粘包现象,UDP永远不会粘包

2.12 黏包成因

2.12.1 TCP协议中的数据传递

##################tcp协议的拆包机制###################

当发送端缓冲区的长度大于网卡的MTU时,tcp会将这次发送的数据拆成几个数据包发送出去。

MTU是Maximum Transmission Unit的缩写。意思是网络上传送的最大数据包。MTU的单位是字节。 大部分网络设备的MTU都是1500。如果本机的MTU比网关的MTU大,大的数据包就会被拆开来传送,这样会产生很多数据包碎片,增加丢包率,降低网络速度。
#########################面向流的通信特点和Nagle算法##############################

TCP(transport control protocol,传输控制协议)是面向连接的,面向流的,提供高可靠性服务。

收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。

这样,接收端,就难于分辨出来了,必须提供科学的拆包机制。 即面向流的通信是无消息保护边界的。

对于空消息:tcp是基于数据流的,于是收发的消息不能为空,这就需要在客户端和服务端都添加空消息的处理机制,防止程序卡住,而udp是基于数据报的,即便是你输入的是空内容(直接回车),也可以被发送,udp协议会帮你封装上消息头发送过去。

可靠黏包的tcp协议:tcp的协议数据不会丢,没有收完包,下次接收,会继续上次继续接收,己端总是在收到ack时才会清除缓冲区内容。数据是可靠的,但是会粘包。

##################基于tcp协议特点的黏包现象成因#############

 

##############socket数据传输过程中的用户态与内核态说明################

例如基于tcp的套接字客户端往服务端上传文件,发送时文件内容是按照一段一段的字节流发送的,在接收方看了,根本不知道该文件的字节流从何处开始,在何处结束

 

此外,发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一个TCP段。若连续几次需要send的数据都很少,通常TCP会根据优化算法把这些数据合成一个TCP段后一次发送出去,这样接收方就收到了粘包数据。

2.12.2 UDP不会发生黏包

UDP(user datagram protocol,用户数据报协议)是无连接的,面向消息的,提供高效率服务。

不会使用块的合并优化算法,, 由于UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址,端口等信息),这样,对于接收端来说,就容易进行区分处理了。 即面向消息的通信是有消息保护边界的。

对于空消息:tcp是基于数据流的,于是收发的消息不能为空,这就需要在客户端和服务端都添加空消息的处理机制,防止程序卡住,而udp是基于数据报的,即便是你输入的是空内容(直接回车),也可以被发送,udp协议会帮你封装上消息头发送过去。

不可靠不黏包的udp协议:udp的recvfrom是阻塞的,一个recvfrom(x)必须对唯一一个sendinto(y),收完了x个字节的数据就算完成,若是y;x数据就丢失,这意味着udp根本不会粘包,但是会丢数据,不可靠。

补充说明:

#####################udp和tcp一次发送数据长度的限制#####################

用UDP协议发送时,用sendto函数最大能发送数据的长度为:65535- IP头(20) – UDP头(8)=65507字节。用sendto函数发送数据时,如果发送数据长度大于该值,则函数会返回错误。(丢弃这个包,不进行发送)

用TCP协议发送时,由于TCP是数据流协议,因此不存在包大小的限制(暂不考虑缓冲区的大小),这是指在用send函数时,数据长度参数不受限制。而实际上,所指定的这段数据并不一定会一次性发送出去,如果这段数据比较长,会被分段发送,如果比较短,可能会等待和下一次数据一起发送。

2.12.3 会发生黏包的两种情况

情况一 发送方的缓存机制

发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包)

#############################服务端#####################

#_*_coding:utf-8_*_

from socket import *

ip_port=('127.0.0.1',8080)

 

tcp_socket_server=socket(AF_INET,SOCK_STREAM)

tcp_socket_server.bind(ip_port)

tcp_socket_server.listen(5)

 

 

conn,addr=tcp_socket_server.accept()

 

 

data1=conn.recv(10)

data2=conn.recv(10)

 

print('----->',data1.decode('utf-8'))

print('----->',data2.decode('utf-8'))

 

conn.close()

 

 
服务端
####################客户端####################

#_*_coding:utf-8_*_

import socket

BUFSIZE=1024

ip_port=('127.0.0.1',8080)

 

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

res=s.connect_ex(ip_port)

 

 

s.send('hello'.encode('utf-8'))

s.send('feng'.encode('utf-8'))
客户端

情况二 接收方的缓存机制

 接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)

#######################服务端#########################

#_*_coding:utf-8_*_

from socket import *

ip_port=('127.0.0.1',8080)

 

tcp_socket_server=socket(AF_INET,SOCK_STREAM)

tcp_socket_server.bind(ip_port)

tcp_socket_server.listen(5)

 

 

conn,addr=tcp_socket_server.accept()

 

 

data1=conn.recv(2) #一次没有收完整

data2=conn.recv(10)#下次收的时候,会先取旧的数据,然后取新的

 

print('----->',data1.decode('utf-8'))

print('----->',data2.decode('utf-8'))

 

conn.close()

 

 
服务端
############################客户端#########################

#_*_coding:utf-8_*_

import socket

BUFSIZE=1024

ip_port=('127.0.0.1',8080)

 

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

res=s.connect_ex(ip_port)

 

 

s.send('hello feng'.encode('utf-8'))
客户端

2.12.4 总结

黏包现象只发生在tcp协议中:

1.从表面上看,黏包问题主要是因为发送方和接收方的缓存机制、tcp协议面向流通信的特点。

2.实际上,主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的

 

2.13 黏包的解决方案一

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

 

###################服务端####################
#_*_coding:utf-8_*_

import socket,subprocess

ip_port=('127.0.0.1',8080)

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

 

s.bind(ip_port)

s.listen(5)

 

while True:

    conn,addr=s.accept()

    print('客户端',addr)

    while True:

        msg=conn.recv(1024)

        if not msg:break

        res=subprocess.Popen(msg.decode('utf-8'),shell=True,\

                            stdin=subprocess.PIPE,\

                         stderr=subprocess.PIPE,\

                         stdout=subprocess.PIPE)

        err=res.stderr.read()

        if err:

            ret=err

        else:

            ret=res.stdout.read()

        data_length=len(ret)

        conn.send(str(data_length).encode('utf-8'))

        data=conn.recv(1024).decode('utf-8')

        if data == 'recv_ready':

            conn.sendall(ret)

    conn.close()

 

 
服务端
##################客户端##################

#_*_coding:utf-8_*_

import socket,time

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

res=s.connect_ex(('127.0.0.1',8080))

 

while True:

    msg=input('>>: ').strip()

    if len(msg) == 0:continue

    if msg == 'quit':break

 

    s.send(msg.encode('utf-8'))

    length=int(s.recv(1024).decode('utf-8'))

    s.send('recv_ready'.encode('utf-8'))

    send_size=0

    recv_size=0

    data=b''

    while recv_size < length:

        data+=s.recv(1024)

        recv_size+=len(data)

 

 

    print(data.decode('utf-8'))
客户端

存在的问题:

程序的运行速度远快于网络传输速度,所以在发送一段字节前,先用send去发送该字节流长度,这种方式会放大网络延迟带来的性能损耗。

 

2.14 解决方案进阶

刚刚的方法,问题在于我们我们在发送

 

我们可以借助一个模块,这个模块可以把要发送的数据长度转换成固定长度的字节。这样客户端每次接收消息之前只要先接受这个固定长度字节的内容看一看接下来要接收的信息大小,那么最终接受的数据只要达到这个值就停止,就能刚好不多不少的接收完整的数据了。

 

2.14.1 struct模块

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

>>> struct.pack('i',1111111111111)

 

struct.error: 'i' format requires -2147483648 <= number <= 2147483647 #这个是范围

 

 

import json,struct

#假设通过客户端上传1T:1073741824000的文件a.txt

 

#为避免粘包,必须自定制报头

header={'file_size':1073741824000,'file_name':'/a/b/c/d/e/a.txt','md5':'8f6fbf8347faa4924a76856701edb0f3'} #1T数据,文件路径和md5值

 

#为了该报头能传送,需要序列化并且转为bytes

head_bytes=bytes(json.dumps(header),encoding='utf-8') #序列化并转成bytes,用于传输

 

#为了让客户端知道报头的长度,用struck将报头长度这个数字转成固定长度:4个字节

head_len_bytes=struct.pack('i',len(head_bytes)) #这4个字节里只包含了一个数字,该数字是报头的长度

 

#客户端开始发送

conn.send(head_len_bytes) #先发报头的长度,4个bytes

conn.send(head_bytes) #再发报头的字节格式

conn.sendall(文件内容) #然后发真实内容的字节格式

 

#服务端开始接收

head_len_bytes=s.recv(4) #先收报头4个bytes,得到报头长度的字节格式

x=struct.unpack('i',head_len_bytes)[0] #提取报头的长度

 

head_bytes=s.recv(x) #按照报头长度x,收取报头的bytes格式

header=json.loads(json.dumps(header)) #提取报头

 

#最后根据报头的内容提取真实的数据,比如

real_data_len=s.recv(header['file_size'])

s.recv(real_data_len)
####################关于struct的详细用法#####################

#_*_coding:utf-8_*_

#http://www.cnblogs.com/coser/archive/2011/12/17/2291160.html

__author__ = 'Linhaifeng'

import struct

import binascii

import ctypes

 

values1 = (1, 'abc'.encode('utf-8'), 2.7)

values2 = ('defg'.encode('utf-8'),101)

s1 = struct.Struct('I3sf')

s2 = struct.Struct('4sI')

 

print(s1.size,s2.size)

prebuffer=ctypes.create_string_buffer(s1.size+s2.size)

print('Before : ',binascii.hexlify(prebuffer))

# t=binascii.hexlify('asdfaf'.encode('utf-8'))

# print(t)

 

 

s1.pack_into(prebuffer,0,*values1)

s2.pack_into(prebuffer,s1.size,*values2)

 

print('After pack',binascii.hexlify(prebuffer))

print(s1.unpack_from(prebuffer,0))

print(s2.unpack_from(prebuffer,s1.size))

 

s3=struct.Struct('ii')

s3.pack_into(prebuffer,0,123,123)

print('After pack',binascii.hexlify(prebuffer))

print(s3.unpack_from(prebuffer,0))

 
关于struct的详细用法

2.14.2 使用struct解决黏包

借助struct模块,我们知道长度数字可以被转换成一个标准大小的4字节数字。因此可以利用这个特点来预先发送数据长度。

发送时

接收时

先发送struct转换好的数据长度4字节

先接受4个字节使用struct转换成数字来获取要接收的数据长度

再发送数据

再按照长度接收数据

 

#################服务端(自定制报头)##################

import socket,struct,json

import subprocess

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它,在bind前加

 

phone.bind(('127.0.0.1',8080))

 

phone.listen(5)

 

while True:

    conn,addr=phone.accept()

    while True:

        cmd=conn.recv(1024)

        if not cmd:break

        print('cmd: %s' %cmd)

 

        res=subprocess.Popen(cmd.decode('utf-8'),

                             shell=True,

                             stdout=subprocess.PIPE,

                             stderr=subprocess.PIPE)

        err=res.stderr.read()

        print(err)

        if err:

            back_msg=err

        else:

            back_msg=res.stdout.read()

 

 

        conn.send(struct.pack('i',len(back_msg))) #先发back_msg的长度

        conn.sendall(back_msg) #在发真实的内容

 

    conn.close()

 
服务端(自定制报头)
#####################客户端(自定制报头)######################

#_*_coding:utf-8_*_

import socket,time,struct

 

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

res=s.connect_ex(('127.0.0.1',8080))

 

while True:

    msg=input('>>: ').strip()

    if len(msg) == 0:continue

    if msg == 'quit':break

 

    s.send(msg.encode('utf-8'))

 

 

 

    l=s.recv(4)

    x=struct.unpack('i',l)[0]

    print(type(x),x)

    # print(struct.unpack('I',l))

    r_s=0

    data=b''

    while r_s < x:

        r_d=s.recv(1024)

        data+=r_d

        r_s+=len(r_d)

 

    # print(data.decode('utf-8'))

    print(data.decode('gbk')) #windows默认gbk编码

 

 
客户端(自定制报头)

2.14.3 使用struct与json序列化解决黏包

我们还可以把报头做成字典,字典里包含将要发送的真实数据的详细信息,然后json序列化,然后用struck将序列化后的数据长度打包成4个字节(4个自己足够用了)

 

发送时

接收时

先发报头长度

先收报头长度,用struct取出来

再编码报头内容然后发送

根据取出的长度收取报头内容,然后解码,反序列化

最后发真实内容

从反序列化的结果中取出待取数据的详细信息,然后去取真实的数据内容

 

#############服务端:定制稍微复杂一点的报头#################

import socket,struct,json

import subprocess

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它,在bind前加

 

phone.bind(('127.0.0.1',8080))

 

phone.listen(5)

 

while True:

    conn,addr=phone.accept()

    while True:

        cmd=conn.recv(1024)

        if not cmd:break

        print('cmd: %s' %cmd)

 

        res=subprocess.Popen(cmd.decode('utf-8'),

                             shell=True,

                             stdout=subprocess.PIPE,

                             stderr=subprocess.PIPE)

        err=res.stderr.read()

        print(err)

        if err:

            back_msg=err

        else:

            back_msg=res.stdout.read()

 

        headers={'data_size':len(back_msg)}

        head_json=json.dumps(headers)

        head_json_bytes=bytes(head_json,encoding='utf-8')

 

        conn.send(struct.pack('i',len(head_json_bytes))) #先发报头的长度

        conn.send(head_json_bytes) #再发报头

        conn.sendall(back_msg) #在发真实的内容

 

    conn.close()

 
服务端:定制稍微复杂一点的报头
#########################客户端#########################

from socket import *

import struct,json

 

ip_port=('127.0.0.1',8080)

client=socket(AF_INET,SOCK_STREAM)

client.connect(ip_port)

 

while True:

    cmd=input('>>: ')

    if not cmd:continue

    client.send(bytes(cmd,encoding='utf-8'))

 

    head=client.recv(4)

    head_json_len=struct.unpack('i',head)[0]

    head_json=json.loads(client.recv(head_json_len).decode('utf-8'))

    data_len=head_json['data_size']

 

    recv_size=0

    recv_data=b''

    while recv_size < data_len:

        recv_data+=client.recv(1024)

        recv_size+=len(recv_data)

 

    print(recv_data.decode('utf-8'))

    #print(recv_data.decode('gbk')) #windows默认gbk编码

 
客户端

2.15 课堂讲解实例解决粘包问题版本1

2.15.1 struct模块的使用

####################struct模块的使用#################

import struct

 

 

headers=struct.pack('i',132333)

# print(headers,len(headers))

 

res=struct.unpack('i',headers)

print(res[0])
struct模块的使用

2.15.2 服务端

###################服务端#############

from socket import *

import subprocess

import struct

 

server=socket(AF_INET,SOCK_STREAM)

server.bind(('127.0.0.1',8093))

server.listen(5)

 

while True:

    conn,client_addr=server.accept()

    print(client_addr)

 

    while True:

        try:

            cmd=conn.recv(8096)

            if not cmd:break

 

            #ls -l;sadfasdf;pwd;echo 123

            obj=subprocess.Popen(cmd.decode('utf-8'),shell=True,

                             stdout=subprocess.PIPE,

                             stderr=subprocess.PIPE

                             )

            stdout=obj.stdout.read()

            stderr=obj.stderr.read()

 

            #1、制作固定长度的报头

            total_size = len(stdout) + len(stderr)

            headers=struct.pack('i',total_size)

 

            #2、先发送命令长度

            conn.send(headers)

 

            #3、发送命令的执行结果

            conn.send(stdout)

            conn.send(stderr)

        except ConnectionResetError:

            break

    conn.close()

 

server.close()

 
服务端

2.15.3 客户端

##########################客户端######################

from socket import *

import struct

 

client=socket(AF_INET,SOCK_STREAM)

client.connect(('127.0.0.1',8093))

 

while True:

    cmd=input('>>: ').strip()

    if not cmd:continue

    client.send(cmd.encode('utf-8'))

 

    #1、先接收命令长度

    headers=client.recv(4)

    total_size = struct.unpack('i', headers)[0]

 

    #2、再收命令的结果

    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()

 
客户端

2.16 课堂讲解实例解决粘包问题版本2

2.16.1 struct模块的使用

##################### struct模块的使用###################

import struct

 

 

# headers=struct.pack('q',13233322222222222)

# print(headers,len(headers))

 

# res=struct.unpack('i',headers)

# print(res[0])

 

import json

 

headers={

    'filepath' : 'a.txt',

    'md5' : '123sxd123x123',

    'total_size' : 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111213123123123123123123111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

}

 

headers_json=json.dumps(headers)

headers_bytes=headers_json.encode('utf-8')

 

# print(len(headers_bytes))

res=struct.pack('i',len(headers_bytes))

print(res,len(res))

 
struct模块的使用

2.16.2 服务端

##########################服务端######################

from socket import *

import subprocess

import struct

import json

 

server=socket(AF_INET,SOCK_STREAM)

server.bind(('127.0.0.1',8093))

server.listen(5)

 

while True:

    conn,client_addr=server.accept()

    print(client_addr)

 

    while True:

        try:

            cmd=conn.recv(8096)

            if not cmd:break

 

            #ls -l;sadfasdf;pwd;echo 123

            obj=subprocess.Popen(cmd.decode('utf-8'),shell=True,

                             stdout=subprocess.PIPE,

                             stderr=subprocess.PIPE

                             )

            stdout=obj.stdout.read()

            stderr=obj.stderr.read()

 

            #1、制作报头

            headers = {

                'filepath': 'a.txt',

                'md5': '123sxd123x123',

                'total_size': len(stdout) + len(stderr)

            }

 

            headers_json = json.dumps(headers)

            headers_bytes = headers_json.encode('utf-8')

 

            #2、先发报头的长度

            conn.send(struct.pack('i',len(headers_bytes)))

 

            #3、发送报头

            conn.send(headers_bytes)

 

            #4、发送命令的执行结果

            conn.send(stdout)

            conn.send(stderr)

        except ConnectionResetError:

            break

    conn.close()

 

server.close()

 
服务端

2.16.3 客户端

######################客户端############################

from socket import *

import struct

import json

 

client=socket(AF_INET,SOCK_STREAM)

client.connect(('127.0.0.1',8093))

 

while True:

    cmd=input('>>: ').strip()

    if not cmd:continue

    client.send(cmd.encode('utf-8'))

 

    #1、先接收报头的长度

    headers_size=struct.unpack('i',client.recv(4))[0]

 

    #2、再收报头

    headers_bytes=client.recv(headers_size)

    headers_json=headers_bytes.decode('utf-8')

    headers_dic=json.loads(headers_json)

    print('========>',headers_dic)

    total_size=headers_dic['total_size']

 

    #3、再收命令的结果

    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()
客户端

2.17 FTP作业:上传下载文件

2.17.1 原博客实例

####################服务端#################

import socket

import struct

import json

import subprocess

import os

 

class MYTCPServer:

    address_family = socket.AF_INET

 

    socket_type = socket.SOCK_STREAM

 

    allow_reuse_address = False

 

    max_packet_size = 8192

 

    coding='utf-8'

 

    request_queue_size = 5

 

    server_dir='file_upload'

 

    def __init__(self, server_address, bind_and_activate=True):

        """Constructor.  May be extended, do not override."""

        self.server_address=server_address

        self.socket = socket.socket(self.address_family,

                                    self.socket_type)

        if bind_and_activate:

            try:

                self.server_bind()

                self.server_activate()

            except:

                self.server_close()

                raise

 

    def server_bind(self):

        """Called by constructor to bind the socket.

        """

        if self.allow_reuse_address:

            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

        self.socket.bind(self.server_address)

        self.server_address = self.socket.getsockname()

 

    def server_activate(self):

        """Called by constructor to activate the server.

        """

        self.socket.listen(self.request_queue_size)

 

    def server_close(self):

        """Called to clean-up the server.

        """

        self.socket.close()

 

    def get_request(self):

        """Get the request and client address from the socket.

        """

        return self.socket.accept()

 

    def close_request(self, request):

        """Called to clean up an individual request."""

        request.close()

 

    def run(self):

        while True:

            self.conn,self.client_addr=self.get_request()

            print('from client ',self.client_addr)

            while True:

                try:

                    head_struct = self.conn.recv(4)

                    if not head_struct:break

 

                    head_len = struct.unpack('i', head_struct)[0]

                    head_json = self.conn.recv(head_len).decode(self.coding)

                    head_dic = json.loads(head_json)

 

                    print(head_dic)

                    #head_dic={'cmd':'put','filename':'a.txt','filesize':123123}

                    cmd=head_dic['cmd']

                    if hasattr(self,cmd):

                        func=getattr(self,cmd)

                        func(head_dic)

                except Exception:

                    break

 

    def put(self,args):

        file_path=os.path.normpath(os.path.join(

            self.server_dir,

            args['filename']

        ))

 

        filesize=args['filesize']

        recv_size=0

        print('----->',file_path)

        with open(file_path,'wb') as f:

            while recv_size < filesize:

                recv_data=self.conn.recv(self.max_packet_size)

                f.write(recv_data)

                recv_size+=len(recv_data)

                print('recvsize:%s filesize:%s' %(recv_size,filesize))

 

 

tcpserver1=MYTCPServer(('127.0.0.1',8080))

 

tcpserver1.run()

 

 

 

 

 

 

#下列代码与本题无关

class MYUDPServer:

 

    """UDP server class."""

    address_family = socket.AF_INET

 

    socket_type = socket.SOCK_DGRAM

 

    allow_reuse_address = False

 

    max_packet_size = 8192

 

    coding='utf-8'

 

    def get_request(self):

        data, client_addr = self.socket.recvfrom(self.max_packet_size)

        return (data, self.socket), client_addr

 

    def server_activate(self):

        # No need to call listen() for UDP.

        pass

 

    def shutdown_request(self, request):

        # No need to shutdown anything.

        self.close_request(request)

 

    def close_request(self, request):

        # No need to close anything.

        pass

 
服务端
#####################客户端##################

import socket

import struct

import json

import os

 

 

 

class MYTCPClient:

    address_family = socket.AF_INET

 

    socket_type = socket.SOCK_STREAM

 

    allow_reuse_address = False

 

    max_packet_size = 8192

 

    coding='utf-8'

 

    request_queue_size = 5

 

    def __init__(self, server_address, connect=True):

        self.server_address=server_address

        self.socket = socket.socket(self.address_family,

                                    self.socket_type)

        if connect:

            try:

                self.client_connect()

            except:

                self.client_close()

                raise

 

    def client_connect(self):

        self.socket.connect(self.server_address)

 

    def client_close(self):

        self.socket.close()

 

    def run(self):

        while True:

            inp=input(">>: ").strip()

            if not inp:continue

            l=inp.split()

            cmd=l[0]

            if hasattr(self,cmd):

                func=getattr(self,cmd)

                func(l)

 

 

    def put(self,args):

        cmd=args[0]

        filename=args[1]

        if not os.path.isfile(filename):

            print('file:%s is not exists' %filename)

            return

        else:

            filesize=os.path.getsize(filename)

 

        head_dic={'cmd':cmd,'filename':os.path.basename(filename),'filesize':filesize}

        print(head_dic)

        head_json=json.dumps(head_dic)

        head_json_bytes=bytes(head_json,encoding=self.coding)

 

        head_struct=struct.pack('i',len(head_json_bytes))

        self.socket.send(head_struct)

        self.socket.send(head_json_bytes)

        send_size=0

        with open(filename,'rb') as f:

            for line in f:

                self.socket.send(line)

                send_size+=len(line)

                print(send_size)

            else:

                print('upload successful')

 

 

 

 

client=MYTCPClient(('127.0.0.1',8080))

 

client.run()

 
客户端

2.17.2 课堂讲解实例

#######################服务端#######################

import socket

import os

import json

import struct

 

SHARE_DIR=r'F:\Python周末20期\day8\08 上传下载文件\SHARE'

 

class FtpServer:

    def __init__(self,host,port):

        self.host=host

        self.port=port

        self.server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

        self.server.bind((self.host,self.port))

        self.server.listen(5)

 

    def serve_forever(self):

        print('server starting...')

        while True:

            self.conn,self.client_addr=self.server.accept()

            print(self.client_addr)

 

            while True:

                try:

                    data=self.conn.recv(1024)  #params_json.encode('utf-8')

                    if not data:break

                    params=json.loads(data.decode('utf-8')) #params=['get','a.txt']

                    cmd=params[0] #

                    if hasattr(self,cmd):

                        func=getattr(self,cmd)

                        func(params)

                    else:

                        print('\033[45mcmd not exists\033[0m')

                except ConnectionResetError:

                    break

            self.conn.close()

        self.server.close()

 

    def get(self,params): #params=['get','a.txt']

        filename=params[1] #filename='a.txt'

        filepath=os.path.join(SHARE_DIR,filename) #

        if os.path.exists(filepath):

            #1、制作报头

            headers = {

                'filename': filename,

                'md5': '123sxd123x123',

                'filesize': os.path.getsize(filepath)

            }

 

            headers_json = json.dumps(headers)

            headers_bytes = headers_json.encode('utf-8')

 

            #2、先发报头的长度

            self.conn.send(struct.pack('i',len(headers_bytes)))

 

            #3、发送报头

            self.conn.send(headers_bytes)

 

            #4、发送真实的数据

            with open(filepath,'rb') as f:

                for line in f:

                    self.conn.send(line)

 

    def put(self):

        pass

 

if __name__ == '__main__':

    server=FtpServer('127.0.0.1',8081)

    server.serve_forever()

 
服务端
#####################客户端#######################

import socket

import struct

import json

import os

 

DOWNLOAD_DIR=r'F:\Python周末20期\day8\08 上传下载文件\DOWNLOAD'

 

class FtpClient:

    def __init__(self,host,port):

        self.host=host

        self.port=port

        self.client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

        self.client.connect((self.host,self.port))

 

    def interactive(self):

        while True:

            data=input('>>: ').strip() #get a.txt

            if not data:continue

            params=data.split() #parmas=['get','a.txt']

            cmd=params[0] #cmd='get'

            if hasattr(self,cmd):

                func=getattr(self,cmd)

                func(params) #func(['get','a.txt'])

 

    def get(self,params):

        params_json=json.dumps(params)

        self.client.send(params_json.encode('utf-8'))

 

        # 1、先接收报头的长度

        headers_size = struct.unpack('i', self.client.recv(4))[0]

 

        # 2、再收报头

        headers_bytes = self.client.recv(headers_size)

        headers_json = headers_bytes.decode('utf-8')

        headers_dic = json.loads(headers_json)

        print('========>', headers_dic)

        filename = headers_dic['filename']

        filesize = headers_dic['filesize']

        filepath = os.path.join(DOWNLOAD_DIR, filename)

 

        # 3、再收真实的数据

        with open(filepath, 'wb') as f:

            recv_size = 0

            while recv_size < filesize:

                line = self.client.recv(1024)

                recv_size += len(line)

                f.write(line)

            print('===>下载成功')

 

if __name__ == '__main__':

    client=FtpClient('127.0.0.1',8081)

    client.interactive()

 

 
客户端

2.18 认证客户端的链接合法性

如果你想在分布式系统中实现一个简单的客户端链接认证功能,又不像SSL那么复杂,那么利用hmac+加盐的方式来实现

2.18.1 服务端

#######################服务端#####################

#_*_coding:utf-8_*_

__author__ = 'Linhaifeng'

from socket import *

import hmac,os

 

secret_key=b'linhaifeng bang bang bang'

def conn_auth(conn):

    '''

    认证客户端链接

    :param conn:

    :return:

    '''

    print('开始验证新链接的合法性')

    msg=os.urandom(32)

    conn.sendall(msg)

    h=hmac.new(secret_key,msg)

    digest=h.digest()

    respone=conn.recv(len(digest))

    return hmac.compare_digest(respone,digest)

 

def data_handler(conn,bufsize=1024):

    if not conn_auth(conn):

        print('该链接不合法,关闭')

        conn.close()

        return

    print('链接合法,开始通信')

    while True:

        data=conn.recv(bufsize)

        if not data:break

        conn.sendall(data.upper())

 

def server_handler(ip_port,bufsize,backlog=5):

    '''

    只处理链接

    :param ip_port:

    :return:

    '''

    tcp_socket_server=socket(AF_INET,SOCK_STREAM)

    tcp_socket_server.bind(ip_port)

    tcp_socket_server.listen(backlog)

    while True:

        conn,addr=tcp_socket_server.accept()

        print('新连接[%s:%s]' %(addr[0],addr[1]))

        data_handler(conn,bufsize)

 

if __name__ == '__main__':

    ip_port=('127.0.0.1',9999)

    bufsize=1024

    server_handler(ip_port,bufsize)

 
服务端

2.18.2 客户端(合法)

#########################客户端(合法)#####################

#_*_coding:utf-8_*_

__author__ = 'Linhaifeng'

from socket import *

import hmac,os

 

secret_key=b'linhaifeng bang bang bang'

def conn_auth(conn):

    '''

    验证客户端到服务器的链接

    :param conn:

    :return:

    '''

    msg=conn.recv(32)

    h=hmac.new(secret_key,msg)

    digest=h.digest()

    conn.sendall(digest)

 

def client_handler(ip_port,bufsize=1024):

    tcp_socket_client=socket(AF_INET,SOCK_STREAM)

    tcp_socket_client.connect(ip_port)

 

    conn_auth(tcp_socket_client)

 

    while True:

        data=input('>>: ').strip()

        if not data:continue

        if data == 'quit':break

 

        tcp_socket_client.sendall(data.encode('utf-8'))

        respone=tcp_socket_client.recv(bufsize)

        print(respone.decode('utf-8'))

    tcp_socket_client.close()

 

if __name__ == '__main__':

    ip_port=('127.0.0.1',9999)

    bufsize=1024

    client_handler(ip_port,bufsize)

 
客户端(合法)

2.18.3 客户端(非法:不知道加密方式)

##########################客户端(非法:不知道加密方式)##################

#_*_coding:utf-8_*_

__author__ = 'Linhaifeng'

from socket import *

 

def client_handler(ip_port,bufsize=1024):

    tcp_socket_client=socket(AF_INET,SOCK_STREAM)

    tcp_socket_client.connect(ip_port)

 

    while True:

        data=input('>>: ').strip()

        if not data:continue

        if data == 'quit':break

 

        tcp_socket_client.sendall(data.encode('utf-8'))

        respone=tcp_socket_client.recv(bufsize)

        print(respone.decode('utf-8'))

    tcp_socket_client.close()

 

if __name__ == '__main__':

    ip_port=('127.0.0.1',9999)

    bufsize=1024

    client_handler(ip_port,bufsize)

 

 
客户端(非法:不知道加密方式)

2.18.4 客户端(非法:不知道secret_key)

#########################客户端(非法:不知道secret_key)###################

#_*_coding:utf-8_*_

__author__ = 'Linhaifeng'

from socket import *

import hmac,os

 

secret_key=b'linhaifeng bang bang bang1111'

def conn_auth(conn):

    '''

    验证客户端到服务器的链接

    :param conn:

    :return:

    '''

    msg=conn.recv(32)

    h=hmac.new(secret_key,msg)

    digest=h.digest()

    conn.sendall(digest)

 

def client_handler(ip_port,bufsize=1024):

    tcp_socket_client=socket(AF_INET,SOCK_STREAM)

    tcp_socket_client.connect(ip_port)

 

    conn_auth(tcp_socket_client)

 

    while True:

        data=input('>>: ').strip()

        if not data:continue

        if data == 'quit':break

 

        tcp_socket_client.sendall(data.encode('utf-8'))

        respone=tcp_socket_client.recv(bufsize)

        print(respone.decode('utf-8'))

    tcp_socket_client.close()

 

if __name__ == '__main__':

    ip_port=('127.0.0.1',9999)

    bufsize=1024

    client_handler(ip_port,bufsize)

 

 
客户端(非法:不知道secret_key)

2.19 socketserver实现并发

解读socketserver源码http://www.cnblogs.com/Eva-J/p/5081851.html

 

2.19.1 server端

########################### server端#####################

import socketserver

class Myserver(socketserver.BaseRequestHandler):

    def handle(self):

        self.data = self.request.recv(1024).strip()

        print("{} wrote:".format(self.client_address[0]))

        print(self.data)

        self.request.sendall(self.data.upper())

 

if __name__ == "__main__":

    HOST, PORT = "127.0.0.1", 9999

 

    # 设置allow_reuse_address允许服务器重用地址

    socketserver.TCPServer.allow_reuse_address = True

    # 创建一个server, 将服务地址绑定到127.0.0.1:9999

    server = socketserver.TCPServer((HOST, PORT),Myserver)

    # 让server永远运行下去,除非强制停止程序

    server.serve_forever()

 
server端

2.19.2 client端

################################# client端#######################

import socket

 

HOST, PORT = "127.0.0.1", 9999

data = "hello"

 

# 创建一个socket链接,SOCK_STREAM代表使用TCP协议

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:

    sock.connect((HOST, PORT))          # 链接到客户端

    sock.sendall(bytes(data + "\n", "utf-8")) # 向服务端发送数据

    received = str(sock.recv(1024), "utf-8")# 从服务端接收数据

 

print("Sent:     {}".format(data))

print("Received: {}".format(received))

 
client端

2.19.3 FtpServer

###########################FtpServer####################

import socketserver

import struct

import json

import os

class FtpServer(socketserver.BaseRequestHandler):

    coding='utf-8'

    server_dir='file_upload'

    max_packet_size=1024

    BASE_DIR=os.path.dirname(os.path.abspath(__file__))

    def handle(self):

        print(self.request)

        while True:

            data=self.request.recv(4)

            data_len=struct.unpack('i',data)[0]

            head_json=self.request.recv(data_len).decode(self.coding)

            head_dic=json.loads(head_json)

            # print(head_dic)

            cmd=head_dic['cmd']

            if hasattr(self,cmd):

                func=getattr(self,cmd)

                func(head_dic)

    def put(self,args):

        file_path = os.path.normpath(os.path.join(

            self.BASE_DIR,

            self.server_dir,

            args['filename']

        ))

 

        filesize = args['filesize']

        recv_size = 0

        print('----->', file_path)

        with open(file_path, 'wb') as f:

            while recv_size < filesize:

                recv_data = self.request.recv(self.max_packet_size)

                f.write(recv_data)

                recv_size += len(recv_data)

                print('recvsize:%s filesize:%s' % (recv_size, filesize))

 

 

ftpserver=socketserver.ThreadingTCPServer(('127.0.0.1',8080),FtpServer)

ftpserver.serve_forever()
FtpServer

2.19.4 FtpClient

########################### FtpClient########################

import socket

import struct

import json

import os

 

 

 

class MYTCPClient:

    address_family = socket.AF_INET

 

    socket_type = socket.SOCK_STREAM

 

    allow_reuse_address = False

 

    max_packet_size = 8192

 

    coding='utf-8'

 

    request_queue_size = 5

 

    def __init__(self, server_address, connect=True):

        self.server_address=server_address

        self.socket = socket.socket(self.address_family,

                                    self.socket_type)

        if connect:

            try:

                self.client_connect()

            except:

                self.client_close()

                raise

 

    def client_connect(self):

        self.socket.connect(self.server_address)

 

    def client_close(self):

        self.socket.close()

 

    def run(self):

        while True:

            inp=input(">>: ").strip()

            if not inp:continue

            l=inp.split()

            cmd=l[0]

            if hasattr(self,cmd):

                func=getattr(self,cmd)

                func(l)

 

 

    def put(self,args):

        cmd=args[0]

        filename=args[1]

        if not os.path.isfile(filename):

            print('file:%s is not exists' %filename)

            return

        else:

            filesize=os.path.getsize(filename)

 

        head_dic={'cmd':cmd,'filename':os.path.basename(filename),'filesize':filesize}

        print(head_dic)

        head_json=json.dumps(head_dic)

        head_json_bytes=bytes(head_json,encoding=self.coding)

 

        head_struct=struct.pack('i',len(head_json_bytes))

        self.socket.send(head_struct)

        self.socket.send(head_json_bytes)

        send_size=0

        with open(filename,'rb') as f:

            for line in f:

                self.socket.send(line)

                send_size+=len(line)

                print(send_size)

            else:

                print('upload successful')

 

 

 

 

client=MYTCPClient(('127.0.0.1',8080))

 

client.run()

 
FtpClient

第3章 作业

 

 

 

 

转载于:https://www.cnblogs.com/maojiong/p/8376496.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在现有省、市港口信息化系统进行有效整合基础上,借鉴新 一代的感知-传输-应用技术体系,实现对码头、船舶、货物、重 大危险源、危险货物装卸过程、航管航运等管理要素的全面感知、 有效传输和按需定制服务,为行政管理人员和相关单位及人员提 供高效的管理辅助,并为公众提供便捷、实时的水运信息服务。 建立信息整合、交换和共享机制,建立健全信息化管理支撑 体系,以及相关标准规范和安全保障体系;按照“绿色循环低碳” 交通的要求,搭建高效、弹性、高可扩展性的基于虚拟技术的信 息基础设施,支撑信息平台低成本运行,实现电子政务建设和服务模式的转变。 实现以感知港口、感知船舶、感知货物为手段,以港航智能 分析、科学决策、高效服务为目的和核心理念,构建“智慧港口”的发展体系。 结合“智慧港口”相关业务工作特点及信息化现状的实际情况,本项目具体建设目标为: 一张图(即GIS 地理信息服务平台) 在建设岸线、港口、港区、码头、泊位等港口主要基础资源图层上,建设GIS 地理信息服务平台,在此基础上依次接入和叠加规划建设、经营、安全、航管等相关业务应用专题数据,并叠 加动态数据,如 AIS/GPS/移动平台数据,逐步建成航运管理处 "一张图"。系统支持扩展框架,方便未来更多应用资源的逐步整合。 现场执法监管系统 基于港口(航管)执法基地建设规划,依托统一的执法区域 管理和数字化监控平台,通过加强对辖区内的监控,结合移动平 台,形成完整的多维路径和信息追踪,真正做到问题能发现、事态能控制、突发问题能解决。 运行监测和辅助决策系统 对区域港口与航运业务日常所需填报及监测的数据经过科 学归纳及分析,采用统一平台,消除重复的填报数据,进行企业 输入和自动录入,并进行系统智能判断,避免填入错误的数据, 输入的数据经过智能组合,自动生成各业务部门所需的数据报 表,包括字段、格式,都可以根据需要进行定制,同时满足扩展 性需要,当有新的业务监测数据表需要产生时,系统将分析新的 需求,将所需字段融合进入日常监测和决策辅助平台的统一平台中,并生成新的所需业务数据监测及决策表。 综合指挥调度系统 建设以港航应急指挥中心为枢纽,以各级管理部门和经营港 口企业为节点,快速调度、信息共享的通信网络,满足应急处置中所需要的信息采集、指挥调度和过程监控等通信保障任务。 设计思路 根据项目的建设目标和“智慧港口”信息化平台的总体框架、 设计思路、建设内容及保障措施,围绕业务协同、信息共享,充 分考虑各航运(港政)管理处内部管理的需求,平台采用“全面 整合、重点补充、突出共享、逐步完善”策略,加强重点区域或 运输通道交通基础设施、运载装备、运行环境的监测监控,完善 运行协调、应急处置通信手段,促进跨区域、跨部门信息共享和业务协同。 以“统筹协调、综合监管”为目标,以提供综合、动态、实 时、准确、实用的安全畅通和应急数据共享为核心,围绕“保畅通、抓安全、促应急"等实际需求来建设智慧港口信息化平台。 系统充分整合和利用航运管理处现有相关信息资源,以地理 信息技术、网络视频技术、互联网技术、移动通信技术、云计算 技术为支撑,结合航运管理处专网与行业数据交换平台,构建航 运管理处与各部门之间智慧、畅通、安全、高效、绿色低碳的智 慧港口信息化平台。 系统充分考虑航运管理处安全法规及安全职责今后的变化 与发展趋势,应用目前主流的、成熟的应用技术,内联外引,优势互补,使系统建设具备良好的开放性、扩展性、可维护性。
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值