网络编程

1.socket模块

两个在网络上的程序通过一个双向的通信连接,实现数据的交换,此连接的一端称为一个socket

socket.socket) 的两种类型

  socket.socket)   ,括号里面不写,默认为是TCP套接字类型。

  socket.socket(type=socket.SOCK_DGRAM)  为UDP套接字类型。

 基于TCP的套接字

服务端

1 ss = socket() #创建服务器套接字
2 ss.bind(address)      #把地址绑定到套接字,常以元(host,port)的形式表示地址。
3 ss.listen()      #监听链接, 括号内的数字表示允许连接的最大数量
4 cs = ss.accept() #接受客户端链接,返回值是一对(conn,adress)#阻塞
5 cs.recv()/cs.send() #对话(接收与发送)
6 cs.close()    #关闭客户端套接字
7 ss.close()        #关闭服务器套接字(可选)

 基于UDP的套接字

服务端

1 ss = socket()   #创建一个服务器的套接字
2 ss.bind()       #绑定服务器套接字
3 inf_loop:       #服务器无限循环
4 cs = ss.recvfrom()/ss.sendto() # 对话(接收与发送)
5 ss.close()           # 关闭服务器套接字

客户端

1 cs = socket()   # 创建客户套接字
2 comm_loop:      # 通讯循环 
3 cs.sendto()/cs.recvfrom()   # 对话(发送/接收)
4 cs.close()      # 关闭客户套接字

2.粘包

  只有TCP有粘包现象,UDP永远不会粘包。

  粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的。

两种情况下会发生粘包。

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

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

  解决方法:为字节流加上自定义固定长度报头,报头中包含字节流长度,然后一次send到对端,对端在接收时,先从缓存中取出定长的报头,然后再取真实数据。

3.struct模块

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

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

发送时:

  先发报头长度

  再编码报头内容然后发送

  最后发真实内容

接收时:

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

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

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

  解决黏包问题

>>>>>:客户端
import
socket import struct import json client = socket.socket() # 创建客户套接字 client.connect(('127.0.0.1',8080)) # 拨号,写的是对方的ip和port,尝试连接服务器 while True: msg = input(">>>:").encode('utf-8') # 输入内容,并编码转化为二进制 if len(msg) == 0:continue # 判断输入数据的长度是否为空 client.send(msg) # 将信息发送给服务器 # 1.先接受字典报头 header_dict = client.recv(4) # 2.解析报头,获取字典长度 dict_size = struct.unpack('i',header_dict)[0] # 3.接收字典数据 dict_bytes = client.recv(dict_size) dict_json = json.loads(dict_bytes.decode('utf-8')) # 4.从字典中获取信息 print(dict_json ) recv_size = 0 real_data = b' ' while recv_size < dict_json.get('file_size'): data = client.recv(1024) real_data += data recv_size += len(data) print(real_data.decode('gbk')) # 用gbk格式打印出来
>>>>>:服务端
import
socket import json import subprocess import struct server = socket.socket() # 创建服务端套接字 server.bind(('127.0.0.1',8080)) # 把地址绑定到套接字 server.listen(5) # 能监听的最大数 while True: conn,addr = server.accept() # 接收客户端链接 while True: try: cmd = conn.recv(1024) # 接收客户端的信息 if len(cmd) == 0:break cmd = cmd.decode('utf-8') # 将接收到的信息解码处理 obj = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) res = obj.stdout.read() + obj.stderr.read() #read是指拿到数据的二进制 d = {"name":"li","file_size":len(res)} # 建立一个字典 json_d = json.dumps(d) # 将字典json序列化处理 # 1.先制作一个字典的报头 header = struct.pack('i',len(json_d)) # 2.发送字典报头 conn.send(header) # 3.发送字典 conn.send(json_d.encode('utf-8')) # 4.再发送真实数据 conn.send(res) except ConnectionResetError: # 排除ConnectionResetError警告 break conn.close()

4.TCP协议和UDP协议

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

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

  数据报协议(自带报头),没有双向通道 通信类似于发短信。

  udp协议客户端允许发空;udp协议不会粘包;udp协议支持并发;udp协议服务端不存在的情况下,客户端照样不会报错。

5.异常处理

什么是异常?

  程序在运行过程中出现了不可预知的错误,并且该错误没有对应的处理机制,那么就会以异常的形式表现出来,造成的影响就是整个程序无法再正常运行。

异常处理的结构分成三种。

  1.异常的类型。2.异常的信息。3.异常的位置

常见的错误类型
1
NAMERROR #名字错误 2 SyntaxError #语法错误 3 KeyError #键不存在 4 ValueError # 值错误 5 IndexError #索引错误

异常的种类
1).语法错误
  是你程序立刻就能解决的,这种错误是不能被容忍的,语法上的错误 发现之后应该立刻解决。

2).逻辑错误
  这种错是可以被容忍的 因为一眼看不出来,针对逻辑上的错误 可以采用异常处理机制进行捕获

原文地址:https://www.cnblogs.com/blue-tea/p/11324131.html