python

★定义

由于不同机器上的程序要通信,才产生了网络

◇C/S架构

server服务端

client客户端

◇B/S架构

 broswer浏览端

server客户端

  如:各种小程序和公众号

★通信

◇网线

连接每一台机器的桥梁

◇网卡

每台计算机有全球唯一的mac地址(物理地址)

◇ARP协议

通过IP地址找到对应的MAC地址

◇交换机

多台机器之间通信的问题

◇网关

局域网中的机器想要访问局域网外的机器,需要网关

◇网段

IP地址和子网掩码按位【与运算】

◇IP协议

  • 127.0.0.1 本地回环地址
  • 为每一台计算机分配IP地址
  • 确定哪些地址在同一个子网络

◇通信协议

TCP协议

  全双工,双方都可以收发信息

  建立通信的过程

  1,建立连接:三次握手

  2,数据传输:长链接

  3,断开连接:四次挥手

UDP协议

是一个简单的传输协议,只把数据发出去,但不能保证它们能到达目的地

◇端口

在计算机上,每一个网络通信的程序,都会开一个端口

端口范围:0-65535

一般情况下我们用:8000之后的端口

◆IP和端口的区别

IP:确定唯一的一台机器

端口:确定唯一的一个程序

★五层模型

◇应用层

  协议:

  • HTTP协议
  • FTP传输协议
  • SMTP协议

◇传输层

选择通信协议

  • TCP
  • UDP

◇网络层

给上一层的信息加上IP信息

  IP协议

◇数据链路层

给上一层的信息加上MAC地址

  ARP协议

◇物理层

  网线网卡

    传输比特流0101010

★socket模块

只要确定了IP和Port,就能使用socket来与之通信

◇类型

  • 基于文件类型:AF_UNIX
  • 基于网络类型:AF_INEF

◇socket实例

基于TCP方式(会黏包)

 1 import socket
 2 
 3 sk = socket.socket()    # 实例socket对象
 4 sk.bind(('127.0.0.1', 8080))    # 绑定ip和端口
 5 sk.listen()             # 监听
 6 
 7 conn, addr = sk.accept()    # 建立连接
 8 conn.send(b'hello')         # 发送消息
 9 res = conn.recv(1024).decode('utf-8')   # 接收消息
10 print(res)
11 conn.close()        # 关闭连接
12 
13 sk.close()      # 关闭socket对象
server.py
1 import socket
2 
3 sk = socket.socket()    # 创建socket对象
4 sk.connect(('127.0.0.1', 8080))     # 创建连接
5 
6 res = sk.recv(1024).decode('utf-8')     # 接收信息
7 print(res)
8 sk.send(b'ok')      # 发送信息
9 sk.close()      # 关闭连接
client.py

基于UDP方式(会丢包)

 1 import socket
 2 
 3 sk = socket.socket(type=socket.SOCK_DGRAM)  # 创建一个基于UDP协议的socket对象
 4 sk.bind(('127.0.0.1', 8080))     # 绑定IP和port
 5 
 6 ret, addr = sk.recvfrom(1024)   # 接收消息 并接收一个 addr
 7 print(ret.decode('utf-8'))
 8 sk.sendto(b'hello',addr)        # 发送消息 需要传addr
 9 
10 sk.close()      # 关闭socket对象
server.py
 1 import socket
 2 
 3 sk = socket.socket(type=socket.SOCK_DGRAM)  # 创建一个基于UDP协议的socket对象
 4 addr = ('127.0.0.1', 8080)
 5 
 6 sk.sendto(b'hi', addr)
 7 ret,addr = sk.recvfrom(1024)        # 接收消息 并接收一个 addr
 8 print(ret.decode('utf-8'))          # 发送消息 需要传addr
 9 
10 sk.close()      # 关闭socket对象
client.py

◇黏包(只在TCP协议中)

原因:面向连接的流传输,数据是无边界的

  1,缓冲机制:不知道客户端发送的数据的长度,recv接收不完的数据,会缓存在内存里,等待下一个recv

  2,优化算法:连续的小数据包会被合并在一起发送,会被一个recv接收

解决办法

发送大的数据前,告诉接收端我要传多大的数据,接收端接收合适的数据大小

通过struct模块

  固定长度的bytes

  pack:就是即将把一个数据转换成固定长度的bytes类型

  unpack:unpack之后拿到的数据是一个元祖

 1 import socket
 2 import struct
 3 
 4 sk = socket.socket()
 5 sk.bind(('127.0.0.1', 8090))
 6 sk.listen()
 7 
 8 conn, addr = sk.accept()
 9 while True:
10     cmd = input('>>>')
11     if cmd == 'q':
12         break
13     conn.send(cmd.encode('gbk'))       # 发命令
14     num = conn.recv(4)
15     num = struct.unpack('i', num)[0]    # unpack之后拿到的数据是一个元祖
16     ret = conn.recv(num).decode('gbk')      # 接收信息
17     print(ret)
18 
19 
20 conn.close()
21 sk.close()
server.py
 1 import socket
 2 import subprocess
 3 import struct
 4 
 5 sk = socket.socket()
 6 sk.connect(('127.0.0.1', 8090))
 7 
 8 while True:
 9     cmd = sk.recv(1024).decode('gbk')   # 接收一个命令
10     if cmd == 'q':
11         break
12     res = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # 在本地执行命令
13     stdout_ret = res.stdout.read()  # gbk字节
14     stderr_ret = res.stderr.read()  # gbk字节
15     num = len(stdout_ret) + len(stderr_ret)
16     sk.send(struct.pack('i', num))      # 把数据包的大小传过去(这个数据包本身4字节)
17     sk.send(stdout_ret)     # 将命令结果发给服务端
18     sk.send(stderr_ret)     # 将命令结果发给服务端
19 
20 sk.close()
client.py
原文地址:https://www.cnblogs.com/sunch/p/9551250.html