c语言基础学python_D08——C语言基础学PYTHON

C语言基础学习PYTHON——基础学习D08

20180829内容纲要:

socket网络编程

1  socket基础概念

2  socketserver

3  socket实现简单的SSH服务器端和客户端

4  粘包

5  小结

6 练习

0  我是小白

先认识一些关键词:

Control Protocol传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,

由IETF的RFC 793定义。在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能,(UDP)是同一层内另一个重要的传输协议。

SSH(SecureShell 。安全外壳协议)由IETF的网络工作小组所指定;SSH为建立在应用层和传输层基础上的安全协议。

SSH是目前较为可靠,专为远程登录会话和其他网络服务提供安全的协议,利用SSH协议可以有效防止远程管理过程中的信息泄露问题,SSH最初是UNIX系统上的一个程序,后来又迅速扩展到其他操作平台。SSH在正确使用时可弥补网络中的漏洞。SSH客户端适用于多种平台。几乎所有UNIX平台—包括HP-UX、Linux、AIX、Solaris、DigitalUNIX、Irix,以及其他平台,都可运行SSH。

FTP(FileTransfer Protocol。文件传输协议)是 TCP/IP 协议组中的协议之一。

FTP协议包括两个组成部分,其一为FTP服务器,其二为FTP客户端。

其中FTP服务器用来存储文件,用户可以使用FTP客户端通过FTP协议访问位于FTP服务器上的资源。

在开发网站的时候,通常利用FTP协议把网页或程序传到Web服务器上。此外,由于FTP传输效率非常高,在网络上传输大的文件时,一般也采用该协议。

1  socket基础概念

socket的英文原义是“孔”或“插座”。作为4BDS UNIX的进程通信机制,取后一种意思。通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。

socket本质上就是在2台网络互通的电脑之间,架设一个通道,两台电脑通过这个通道来实现数据的互相传递。

网络通信都是基于ip+port 方能定位到目标的具体机器上的具体服务,操作系统有0-65535个端口,每个端口都可以独立对外提供服务

如果 把一个公司比做一台电脑 ,那公司的总机号码就相当于ip地址, 每个员工的分机号就相当于端口, 你想找公司某个人,必须 先打电话到总机,然后再转分机 。

建立一个socket必须至少有2端, 一个服务端,一个客户端, 服务端被动等待并接收请求,客户端主动发起请求, 连接建立之后,双方可以互发数据。

话不多先来看一段最简单的代码:

服务器端:

Socket( ):第一步创建一个 socket 对象,这是用来封装 TCP/IP的过程,之后就可以利用它来发送 TCP 或者是 UDP. e.g. s = socket.socket( )

bind( ):第二步是绑定 IP 和端口,它接受一个元组类型的数据。e.g. s.bind(('127.0.0.1',8088,))

listen( ):第三步是定义最多能挂起的数目,e.g. s.listen(2),意思说你当前允许一个客户端在连接,两个客户端在等待发送消息(挂起)。

accept( ):第四步是创建客户端和服务端之间的那条连接 conn,程序在连接前会处于挂起的状态。 e.g. conn, addr = s.accept( )

客户端:

Socket( ):第一步创建一个 socket 对象,这是用来封装 TCP/IP的过程,之后就可以利用它来发送 TCP 或者是 UDP. e.g. s = socket.socket( )

connect( ):第二步客户端用自己的对象来连接服务端,它接受一个元组类型的数据。e.g. s.connect(('127.0.0.1',8088,))

1 #Author:ZhangKanghui

2

3 importsocket4 server =socket.socket()5 #绑定要监听的端口

6 server.bind(('localhost',6969))7 server.listen() #监听

8

9 print("我的心在等待!")10 #server.accept() 这个地方不能直接接听,如果这样的话就只能有一个接入

11 conn,addr = server.accept() #等待

12 #coon就是客户端连过来而在服务器端为其生成的一个链接实例

13 #print(conn,addr) 可以通过这样来看看接听了什么

14 print(conn,addr)15

16 print("一直在等待!")17 data =conn.recv(1024)18 print("recv:",data)19

20

21 conn.send(data.upper())22 server.close()

socket_server(基础版)

1 #Author:ZhangKanghui

2

3 importsocket4 #首先声明socket类型,同时生成socket链接对象

5 client =socket.socket()6 #family =AF_INET他就是地址簇,默认就是IPv4,type=SOCK_STWEAM他就是TCP/TCP

7

8 client.connect(('localhost',6969)) #只能传一个参数,所以把链接地址端口放进一个元组。

9 #发送数据

10 client.send(b"hello world") #发送的数据必须是bytes类型

11 #那么能不能发送中文呢

12 #client.send("study 使我快乐".encode("utf-8"))

13 #如果想输出中文

14 #client.send("我想要mopney".encode("utf-8"))

15 #接受服务器的返回

16 data =client.recv(1024) #buffersize缓冲区空间容量,1024字节=1K

17 print("recv:",data)18 #如果要输出中文

19 #print("recv:",data.decode())

20 client.close()

socket_client(基础版)

接下来依次启动服务器端和客户端:

先启动服务器端:

再启动客户端:

再看服务器端接收了什么?

这么看来基本的功能已经实现了。那么这有没有什么漏洞呢?在执行一次客户端试试看?

这是因为现在还只能接收一个,不能实现并发。c面会有学习。别急慢慢来~而且只能发送一条指令,接收一条指令,这能干毛线啊?

磨刀不误砍柴工,先来看一些基础:关于server =socket.socket()

Socket Families(地址簇)

socket.AF_UNIX unix本机进程间通信

socket.AF_INET IPV4

socket.AF_INET6  IPV6

Socket Types

socket.SOCK_STREAM  #for tcp

socket.SOCK_DGRAM   #for udp

socket.SOCK_RAW   #原始套接字。利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。

那么,现在对上面的代码开始进行优化:只能收发一条但是能够实现多用户收发。

1 #Author:ZhangKanghui

2

3 importsocket4 server =socket.socket()5

6 server.bind(('localhost',6969))7 server.listen()8 print("我的心在等待!")9

10 whileTrue:11 conn,addr =server.accept()12 print(conn,addr)13 print("一直在等待!")14 data =conn.recv(1024)15 print("recv:",data)16 conn.send(data.upper())17 server.close()

服务器端

1 #Author:ZhangKanghui

2

3 importsocket4

5 client =socket.socket()6

7 client.connect(('localhost',6969))8 whileTrue:9 msg = input(">>:").strip()10

11 client.send(msg.encode("utf-8"))12 data =client.recv(1024)13 print("recv:",data)14

15 client.close()

客户端

通过运行结果可以发现,每个客户端只能像服务器发送一条数据,下条会自动挂起,因为这个时候服务器在等待第二个响应。

那么接下来怎么再次优化呢?一个用户可以多次收发,但不支持多用户同时收发。

只需要对服务器端进行修改即可:

1 #Author:ZhangKanghui

2

3 importsocket4 server =socket.socket()5

6 server.bind(('localhost',6969))7 server.listen()8 print("我的心在等待!")9 conn,addr =server.accept()10 print(conn,addr)11 print("一直在等待!")12

13 whileTrue:14 data =conn.recv(1024)15 print("recv:",data)16 conn.send(data.upper())17 server.close()

服务器端

问题又来了,不能支持多用户,如果先断开,那第二个客户端能不能连进来呢?不能

1 #Author:ZhangKanghui

2

3 importsocket4 server =socket.socket()5

6 server.bind(('localhost',9999))7 server.listen()8 conn,addr =server.accept()9 print(conn,addr)10 print("一直在等待!")11 print("我的心在等待!")12

13 whileTrue:14 try:15 #conn,addr = server.accept()

16 #print(conn,addr)

17 #print("一直在等待!")

18 data =conn.recv(1024)19 print("recv:",data)20 conn.send(data.upper())21 exceptConnectionResetError as e:22 print("Error",e)23 break

24 server.close()

服务器端改进

当客户端断开时可以通过捕获异常让程序正常进行。这样才能继续接收第二个。

2 socketserver

The socketserver module simplifies the task of writing network servers.

There are five classes in an inheritance diagram, four of which represent synchronous servers of four types:

主要介绍TCPserver:

classsocketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)

This uses the Internet TCP protocol, which provides for continuous streams of data between the client and server. If bind_and_activate is true,

the constructor automatically attempts to invoke server_bind() andserver_activate().

The other parameters are passed to the BaseServer base class.

创建一个socketserver步骤:

1 first,you must create a request handler class by subclassing the BaseRequestHandler  class and overrinding(覆盖) its handle() method ;

this method will process incoming request.

你必须创建一个请求处理类,并且这个类要继承BaseRequestHandler,并且还要覆盖父类里的handle()

2 second, you must instantiate one of the server classes, passing its server's address and the request handler class.

你必须实例化TCPServer,并且传递server ip和上面创建的请求处理类传给TCPServer。

3 third, call the handle_request() or server_forever() method of the server object to process one or many requests.

server.handle_request()   #只处理一个请求

server.handle_forever()   #处理多个请求,永远执行

4 finally, call server_close() to close the socket.

那么接下来就创建一个socketserver:

1 #Author:ZhangKanghui

2

3 importsocketserver4

5 classMyTCPHandler(socketserver.BaseRequestHandler):6 """

7 The request handler class for our server.8

9 It is instantiated once per connection to the server, and must10 override the handle() method to implement communication to the11 client.12 """

13 #跟客户端的所有交互都是在handle中完成的

14 defhandle(self):15 whileTrue:16 try:17 #self.request is the TCP socket connected to the client

18 self.data = self.request.recv(1024).strip()19 print("{} wrote:".format(self.client_address[0])) #打印客户端的ip地址

20 print(self.data)21 #just send back the same data, but upper-cased

22 self.request.sendall(self.data.upper())23 exceptConnectionResetError as e:24 print("Error",e)25 break

26

27

28 if __name__ == "__main__":29 HOST, PORT = "localhost", 9999

30

31 #Create the server, binding to localhost on port 9999

32 server =socketserver.TCPServer((HOST, PORT), MyTCPHandler)33 #实例化

34 server.serve_forever()

Socketserver

1 #Author:ZhangKanghui

2

3 importsocket4 client =socket.socket()5 client.connect(('localhost',9999))6 whileTrue:7 msg = input(">>:").strip()8 if len(msg) == 0: continue

9 client.send(msg.encode("utf-8"))10 data =client.recv(1024)11 print("recv:",data)12

13 client.close()

Client

此时,能不能支持多并发呢?我们可以多次启动客户端,发现不能。只有先断开1才会执行2,断开2才会执行3。

那么如何实现多并发呢?其实很简单。 只需要在服务器端修改TCPServer为ThreadingTCPServer即可。

ThreadingTCPServer就是多线程。什么事多线程呢?看后续

3 socket实现简单的SSH服务器端和客户端

通过os模块调用命令行。

1 #Author:ZhangKanghui

2 importos3 importsocket4 server =socket.socket()5 server.bind(('localhost',9999))6

7 server.listen()8

9 whileTrue:10 conn,addr =server.accept()11 print("new coon",addr)12 whileTrue:13 data = conn.recv(1024)14 if notdata:15 print("客户端已断开")16 break

17 print("执行指令:",data)18 cmd_res =os.popen(data.decode()).read()19 if len(cmd_res) ==0:20 cmd_res = "cmd has no output"

21

22 conn.send(cmd_res.encode("utf-8"))23

24 server.close()

SSH服务器端

1 #Author:ZhangKanghui

2

3 importsocket4 client =socket.socket()5

6 client.connect(('localhost',9999))7

8 whileTrue:9 cmd = input(">>:").strip()10 if len(cmd) == 0:continue

11 client.send(cmd.encode("utf-8"))12 cmd_res = client.recv(1024)13

14 print(cmd_res.decode())15

16 client.close()

SSH客户端

当使用存在的指令时,会有正常输出,但是当指令不存在时,通过判断让程序正常进行了。这个以后会有更好的解决办法

可以通过以下几个指令试一下,看一下执行结果

dir  pwd  ipconfig

运行结果会发现竟然不全,那究竟是为什么呢?客户端接收1024剩下存在服务器端的内存里,就一直存在缓冲区中,如果不接收完会影响下一条指令的正常输出。

那么怎样能够接收完呢?

思路是这样的,在服务器端发送给客户端时先判断数据大小,客户端接收数据大小之后,可以通过循环每次1024接收,直至传输完毕。

修改之后代码是这样的。可以试试对比一下有什么不同?再次执行ipconfig

1 #Author:ZhangKanghui

2 importos3 importsocket4 server =socket.socket()5 server.bind(('localhost',9999))6

7 server.listen()8

9 whileTrue:10 conn,addr =server.accept()11 print("new coon",addr)12 whileTrue:13 data = conn.recv(1024)14 if notdata:15 print("客户端已断开")16 break

17 print("执行指令:",data)18 cmd_res =os.popen(data.decode()).read()19 if len(cmd_res) ==0:20 cmd_res = "cmd has no output"

21 conn.send(str(len(cmd_res.encode())).encode("utf-8")) #先发大小给客户端

22 conn.send(cmd_res.encode("utf-8"))23

24 server.close()

SSH服务器端

1 #Author:ZhangKanghui

2

3 importsocket4 client =socket.socket()5

6 client.connect(('localhost',9999))7

8 whileTrue:9 cmd = input(">>:").strip()10 if len(cmd) == 0:continue

11 client.send(cmd.encode("utf-8"))12 cmd_res_size = client.recv(1024) #先接收命令结果的大小

13 print("命令结果大小:",cmd_res_size)14

15 received_size =016 #received_data = b''

17 while received_size !=int(cmd_res_size.decode()):18 data = client.recv(1024)19 received_size+=len(data)20 print(received_size)21 print(data.decode())22 else:23 print("cmd res received done",received_size)24

25 cmd_res = client.recv(1024)26

27 print(cmd_res.decode())28

29 client.close()

SSH客户端

我们看一下服务器中的一段代码:

两次发送,系统有时会把它们合在一起发出去,就出现了粘包~!因为不知道缓冲区什么时候会把这两条命令放在一起。

那下面来了解一下粘包。

4 粘包

TCP粘包是在一次接收数据不能完全地体现一个完整的消息数据。TCP通讯为何存在粘包呢?

主要原因是TCP是以流的方式来处理数据,再加上网络上MTU的往往小于在应用处理的消息数据,所以就会引发一次接收的数据无法满足消息的需要,导致粘包的存在。

那么我们如何解决呢?

第一种解决方法:

首先通过一种缓冲区接收数据超时,发送命令来间隔两次命令传输,但这样的后果就是延长数据传输时间,降低了传输效率。

这种方法显然不太可取。太low了~!

下面来个正确姿势解决粘包:

第二种解决方法:

让客户端给服务器端一个确认指令,通过确认指令间隔两次命令传输,这样就能阻隔两次命令的粘包。

1 #Author:ZhangKanghui

2 importos3 importtime4 importsocket5 server =socket.socket()6 server.bind(('localhost',9999))7

8 server.listen()9

10 whileTrue:11 conn,addr =server.accept()12 print("new coon",addr)13 whileTrue:14 data = conn.recv(1024)15 if notdata:16 print("客户端已断开")17 break

18 print("执行指令:",data)19 cmd_res =os.popen(data.decode()).read()20 if len(cmd_res) ==0:21 cmd_res = "cmd has no output"

22 conn.send(str(len(cmd_res.encode())).encode("utf-8")) #先发大小给客户端

23 #time.sleep(0.5)

24 client_ack = conn.recv(1024) #等待客户端确认,不然就在这里挂起,从而完成上一条发送命令与下一条隔开,解决粘包

25 print("ack from client:",client_ack)26 conn.send(cmd_res.encode("utf-8"))27

28 server.close()

服务器端

1 #Author:ZhangKanghui

2

3 importsocket4 client =socket.socket()5

6 client.connect(('localhost',9999))7

8 whileTrue:9 cmd = input(">>:").strip()10 if len(cmd) == 0:continue

11 client.send(cmd.encode("utf-8"))12 cmd_res_size = client.recv(1024) #先接收命令结果的大小

13 print("命令结果大小:",cmd_res_size)14 client("防止粘包发送的确定指令")15

16 received_size =017 #received_data = b''

18 while received_size !=int(cmd_res_size.decode()):19 data = client.recv(1024)20 received_size+=len(data)21 print(received_size)22 print(data.decode())23 else:24 print("cmd res received done",received_size)25

26 cmd_res = client.recv(1024)27

28 print(cmd_res.decode())29

30 client.close()

客户端

第三种方法:

通过服务器发送给客户端需要接受数据的大小,然后客户端自己判断大小通过每次接1024,最后一次把剩下的接收。也就是说刚好接受文件大小,再继续接受下一个。

这样也能解决粘包问题。同时下面的代码中对文件的传输还进行了MD5加密。关于ftp

ftp server:

1 读取文件名

2 检测文件是否存在

3 打开文件

4 检测文件大小

5 发送文件大小给客户端

6 等待客户端确认

7 开始边读边发数据

8 发送md5

1 #Author:ZhangKanghui

2 importos3 importtime4 importsocket5 importhashlib6 server =socket.socket()7 server.bind(('localhost',9999))8

9 server.listen()10

11 whileTrue:12 conn,addr =server.accept()13 print("new coon",addr)14 whileTrue:15 data = conn.recv(1024)16 if notdata:17 print("客户端已断开")18 break

19 cmd,filename =data.decode().split()20 print(filename)21 ifos.path.isfile(filename):22 f = open(filename,'rb')23 m =hashlib.md5()24 file_size =os.stat(filename).st_size25 conn.send(str(file_size.encode())) #send file size

26 conn.recv(1024) #wait for ack

27 for line inf:28 m.update(line)29 conn.send(line)30 print("file md5:",m.hexdiggest())31 f.close()32 conn.send(m.hexdiggest().encode()) #send md5

33 server.close()

ftp服务器端

1 #Author:ZhangKanghui

2

3 importsocket4 importos5 importhashlib6 client =socket.socket()7

8 client.connect(('localhost',9999))9

10 whileTrue:11 cmd = input(">>:").strip()12 if len(cmd) == 0:continue

13 if cmd.startswith("get"):14 client.send(cmd.encode())15 server_reponse = client.recv(1024)16 print("server response:",server_reponse)17 client.send(b"i am ready to recv file")18 file_total_size =int(server_reponse.decode())19 received_size =020 filename = cmd.split()[1]21 f =open(filename +'.new','wb')22 m =hashlib.md5()23 while received_size <24 if file_total_size received_size>1024: #表示要收不止一次24>

25 size =1024

26 else: #最后一次剩多少收多少

27 size =file_total_size -received_size28 print("last recv:",size)29

30 data =client.recv(size)31 received_size+=len(data)32 m.update(data)33 f.write(data)34 #print(file_total_size,received_size)

35 else:36 new_file_md5 =m.hexdigest()37 print("flie recv done",file_total_size,received_size)38 f.close()39 server_file_md5 = client.recv(1024)40 print("server file md5",server_file_md5)41 print("client file md5",new_file_md5)42 client.close()

ftp客户端

5 小结

真的不懂,可能以后会明白的。

安慰别人的话说服不了自己。

间歇性踌躇满志,持续性混吃等死~!

6 练习

作业:开发一个支持多用户在线的FTP程序

要求:

用户加密认证

允许同时多用户登录

每个用户有自己的家目录 ,且只能访问自己的家目录

对用户进行磁盘配额,每个用户的可用空间不同

允许用户在ftp server上随意切换目录

允许用户查看当前目录下文件

允许上传和下载文件,保证文件一致性

文件传输过程中显示进度条

附加功能:

新建目录mkdir

.查看当前工作目录的路径pwd

如果对一些基础概念还不够明确,或者这篇博客的逻辑不过清晰,可以看这里

6.1 程序目录结构

服务器端

客户端

都看到这里了,如果真的想弄明白,那就看这篇博客吧,我自己也不会。以后看明白了再补上。说出这句话自己心里都没底气。

我是尾巴~

可以说是非常用心了!

虽不才,才要坚持。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园2.0是高校信息化建设的新阶段,它面对着外部环境变化和内生动力的双重影响。国家战略要求和信息技术的快速发展,如云计算、大数据、物联网等,为智慧校园建设提供了机遇,同时也带来了挑战。智慧校园2.0强调以服务至上的办理念,推动了教育模式的创新,并对传统人才培养模式产生了重大影响。 智慧校园建设的解决之道是构建一个开放、共享的信息化生态系统,利用互联网思维,打造柔性灵活的基础设施和强大的基础服务能力。这种生态系统支持快速迭代的开发和持续运营交付能力,同时注重用户体验,推动服务创新和管理变革。智慧校园的核心思想是“大平台+微应用+开放生态”,通过解耦、重构和统一运维监控,实现服务复用和深度融合,促进业务的快速迭代和自我演化。 智慧校园的总体框架包括多端协同,即“端”,它强调以人为中心,全面感知和捕获行为数据。这涉及到智能感知设备、超级APP、校园融合门户等,实现一“码”或“脸”通行,提供线上线下服务端的无缝连接。此外,中台战略是智慧校园建设的关键,包括业务中台和数据中台,它们支持教育资源域、教服务域等多个领域,实现业务的深度融合和数据的全面治理。 在技术层面,智慧校园的建设需要分期进行,逐步解耦应用,优先发展轻量级应用,并逐步覆盖更多业务场景。技术升级路径包括业务数据化、数据业务化、校园设施智联化等,利用IoT/5G等技术实现设备的泛在互联,并通过人工智能与物联网技术的结合,建设智联网。这将有助于实现线上线下一网通办,提升校园安全和习生活体验,同时支持人才培养改革和后勤管理的精细化。 智慧校园的建设不仅仅是技术的升级,更是对教育模式和管理方式的全面革新。通过构建开放、共享的信息化生态系统,智慧校园能够更好地适应快速变化的教育需求,提供更加个性化和高效的服务,推动教育创新和人才培养的高质量发展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值