python31 网络编程socket使用

复习

1.C/S结构

2.网络通讯

3.OSI 开放式系统互联参考模型 七层模型

详解:
 

1.C/S结构

​ client    server
​ 网络通讯是为了共享数据
​ 拥有数据的一方 称之为服务器server
​ 需要数据的一方称之为客户端client
 B/S
​ 浏览器  服务器
​ 

2.网络通讯

​     1.物理连接介质
​     2.通讯协议     (使双方能看懂数据)
​       协议即标准/规范   发送方和接收需要共同遵守
 

3.OSI 开放式系统互联参考模型 七层模型

 
​                        应用层  表示层 会话层  传输层  网络层  数据链路层 物理层  
​ 
​ 应用层(应用层  表示层 会话层)
​ 传输层 
​ 网络层 
​ 网络接口层( 数据链路层 物理层  )
​ 

1) 物理层

​ 定义一堆物理相关协议 例如接口外观等
​ 有了物理层就能传输二进制数据    010101010101010

2) 数据链路层

​        主要是以太网协议 

​          1.数据传输格式   数据帧
​            [head  |  data]
​  
​           2.每个设备要联网 必须具备网卡  每个网卡拥有一个全球唯一的MAC地址
​            数据链路层通过广播的方式来查找某一台计算机 
​            在这一层 出现了交换机   用于组成一个局域网 
​             在局域网中要查找某一台计算机  就通过广播的方式
​             如果每一次都需要广播 就浪费资源了, 所以交换机会自动保存 网口和MAC地址表的映射关系
​ 
          问题: 广播风暴   没有交换机可以同时处理所有计算机 

3) 网络层

​           主要是ip协议
            1. 每一台设备都必须有一个ip地址
                       格式: 四段三位点分十进制    0.0.0.0-255.255.255.255
                       其中前三段是网络号(常规情况下)   最后一段是主机号
            2.ip数据包  格式
                       [ 以太帧头  |   [head | data] ]
   
              3.子网掩码
    ​                   用于标示iP中哪些是网络号 哪些是主机号
                               ​ 255.255.255.0
    ​                           11111111.11111111.11111111.0000000
    ​                         1表示网络号  0标示主机号
    ​ 
                             ​ 将ip转为二进制  子网掩码转为二进制 
    ​                            使用AND来计算两个ip是否处于同一局域网
   
    ​                         例如 1号ip 转换的结果如下
    ​                                  11011111.00001111.10101010.00001
    ​                                  11111111.11111111.11111111.0000000
                             结果: 11011111.00001111.10101010.00000
   
    ​                       例如 1号ip 转换的结果如下
    ​                              11011111.00001111.10101010.00010
                                 ​ 11111111.11111111.11111111.0000000
                        ​ 结果: 11011111.00001111.10101010.00000
    ​ 
                  4. ARP    Address Resolution Protocol
    ​                       该协议用于将ip转为MAC地址  
    ​                     1.先 比对子网掩码 判断两个ip是否处于同一子网中
    ​                     2.1如果是  则直接在当前局域网中进行广播 
    ​                     2.2如果不是 同一局域网  则将数据包发送对方的网关   
                        ​ 2.3对方网关收到数据包后回复自己的MAC地址  
    ​                     2.4发送的交换机收到数据包在发送给 发送方 同时存储对方网关与MAC的对应关系
    ​                     2.5发送已经明确 对方网关的MAC 以及对方的IP 
    ​                     3.发送数据
    ​                      [我的MAC  对方网关的MAC [我的ip 对方的ip]]
   
                    5.路由协议:
    ​                          找到一条最佳的路径 
   
                      到此可以使用IP 来定位到全球的某一个局域网 中的某一台计算机
   

   4)传输层

    ​                   1.端口号

    ​                        每个应用程序都必须绑定一个端口号,用于标识你是谁   是qq还是微信
    ​                        端口号不能重复
    ​                       端口号就是一个整形数字   取值范围0-65535   0-1023为系统保留端口
    ​                        有了ip和端口号就能 定位到全球某一台计算机上的某一个应用程序
    ​ 

    ​                    2.传输层主要的传输协议

    ​ 
    ​                                 TCP (传输控制协议)    就像打电话
    ​                          可靠传输  
    ​                          如何保障可靠
    ​                        1.三次握手建立链接  其目的是为了确认传输路径可用
    ​                        2.传输过程中 每一个数据包都需要 确认信息 
    ​                        3.四次挥手断开链接   是为了保障双方数据都已经传输完毕 
    ​  
    ​                           传输效率低
    ​ 
    ​                                  UDP       像是校园广播 
    ​                                  用户数据报协议 
    ​                                  不关心数据是否传输成功  ,甚至不关心是否存在 
    ​  
    ​                            优点:传输效率高 

    ​ 

   5) 应用层

    ​ 数据已经通过下面各种协议传入了应用程序 
    ​ 应用程序该如何解析这些数据 ,用它们来干什么 
    ​ 这就是应用程序协议需要关心的问题了
    ​ 每个应用程序都可以自己定义自己的协议 只要客户端程序和服务器程序能看懂就行 
    ​ HTTP/HTTPS  SMTP  FTP  
   
   
   

今日内容

网络编程之socket

 1.socket在OSI中的位置     

1.socket在OSI中的位置     

1.1socket

​ 什么是socket  翻译为套接字
​ 是一套编程接口,内部封装了一堆底层协议,隐藏了内部复杂的实现细节,提供简单的使用接口
​ 咱们只要按照socket编程接口来编写出的代码,就已经遵循了各种协议 
​ 简单的说就是一个封装好的模块
​ 要学习的就是模块的使用方法 
 

1.2socket的发展 

​ 最开始socket使用来完成进程间通讯的,并不是用来网络通讯,那时候还没有网络
​ 后来有了网络之后 .基于之前的socket来进行了更新  使其可以支持网络通讯
​ 所以socket分为两种类型 
​ AF_UNIX : 进程间通讯
​ AF_INET : 网络通讯  
 

1.3 socket在OSI中的位置

案例说明:

  socket客户端.py

import socket

1.# 买个电话
client = socket.socket()

# 作为客户端 ip和端口可以变化 所有系统会自动分配随机端给客户端
client.connect(("127.0.0.1",1688))

2.# 开始通话
# 发送数据 注意发送的内容只能是二进制 bytes
client.send("hello".encode("utf-8"))

3.# 接收数据 单位为字节
data = client.recv(1024)
print(data)

client.close()
 
 
 

   socket服务器.py

import socket

# 作为服务器必明确自己的ip和端口号 并且不应该变化
# 参数1指定 socket类型AF_INET 表示网络类型
#参数2指定的传输协议为 SOCK_STREAM表示TCP协议 SOCK_DGRAM UDP协议
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 1.买电话机

# 默认就是网络类型 TCP协议
#server = socket.socket()

# 127.0.0.1这叫回送地址 表示当前电脑本身
# ip一定本机ip 本机可能会有多个IP (无线|有限)
# 注意:需要参数是一个元组 端口就是普通整数
server.bind(("127.0.0.1",1688)) # 2.插入手机卡

# 无论是服务器端还是客户端 都是socket 类型

# 开始监听1688端口 盯着这个端口看以后没有数据过来
server.listen() # 3.手机开始待机

# 接收链接请求
# 第一个是表示客户端的socket 第二个客户端的地址信息
client,addr = server.accept() # 4.接电话
# print(type(client))
# print(addr)


# 5.收发数据
data = client.recv(1024)
print(data)
client.send("copy!".encode("utf-8"))

server.close() # 关机
 1.4常见的异常:
 
  1.端口占用问题
# 如果已经开启了服务器  再次运行将会抛出 端口占用异常  把之前开启的服务器关掉即可
"""
有些情况   明明已经关闭了进程 但是 还是端口占用 
可能是进程正在后台运行  可以通过端口查出进程  进行关闭
windows下
netstat -ano  | findstr 9898
tasklist | findstr 进程id    拿到进程名称
taskkill /f /t /im 进程名称

大招: 重启电脑
 
案例:说明
import socket
server = socket.socket()

server.bind(("127.0.0.1",9891))
server.listen()
server.accept()

server.close()


# 如果已经开启了服务器 再次运行将会抛出 端口占用异常 把之前开启的服务器关掉即可
"""
有些情况 明明已经关闭了进程 但是 还是端口占用
可能是进程正在后台运行 可以通过端口查出进程 进行关闭
windows下
netstat -ano | findstr 9898
tasklist | findstr 进程id 拿到进程名称
taskkill /f /t /im 进程名称

大招: 重启电脑
"""

     2.常见异常实例

服务器.py
import socket

server = socket.socket()

server.bind(("127.0.0.1",8888)) # 只有服务器需要绑定

server.listen()

# accept 是一个阻塞函数 会一直等到有客户端链接过来 在继续执行
client,addr = server.accept() # 完成了三次握手
# print(client)
# print(addr)

print("握手成功!")
# 收发数据 注意都是用表示客户端的socket来收发数据
# client.send("world".encode("utf-8"))

import time
time.sleep(3)
try:
# data = client.recv(1024)
# print("客户端发来的数据:", data)
# 发送数据时 对方可能也会异常下线 也会抛出异常
# 接收数据 和发送数据都应该放到try
client.send("test".encode("utf-8"))

except:
print("client 下线了")
# 断开链接
client.close() # 完成四次挥手


server.close()
print("服务器关机!")
 
客户端.py
import socket

client = socket.socket()

# connect本质实在进行三次握手 也是一个数据传输的过程 如果服务器没有立马响应 也会阻塞
#
client.connect(("127.0.0.1",8888)) # 三次握手
print("握手成功! client")


# 发送数据 本质上是把数据交给操作系统来进行发送 一旦数据交给了操作系统 后续的发送
# 应用程序就无法控制了 ,send一般不会卡 当然 如果数据量很大就会阻塞
# client.send("hello".encode("utf-8"))
# print("发送完成")

# 是从操作系统缓存区读取数据 如果当前还没有任何数据 就会进入阻塞
# 会一直等到有数据到来 再继续执行
# try:
# data = client.recv(1024)
# print("接收完成!")
# print(data)
# except:
# print("服务器 强行下线了!")


import time
time.sleep(10)
# 客户端执行close 是正常关闭链接 会给服务器送空字节 用于表示要断开链接
client.close()
print("关机了!")


1.5加上循环
服务器.py
import socket
server = socket.socket()
server.bind(("127.0.0.1",8989))
server.listen()

while True:
client_socket,client_addr = server.accept()
buffer_size = 1024 #缓冲区  就是一个临时的容器  
# 缓冲区大小 不能随便写 太大会导致内存溢出 太小效率低 在内存能够承受的情况下 大一些

while True:
try:
data = client_socket.recv(1024)
# 在linux中 对方如果强行下线了 服务器不会抛出异常 只会收到空消息
# 得加上判断 如果为空则意味着 对方下线了 应该关闭链接 跳出循环
# windows上正常关闭 也会收到空消息 if 必须要加
if not data:
client_socket.close()
break

print(data.decode("utf-8")) # 解码时必须保证双方同意编码方式
# 转为大写在发回去
client_socket.send(data.upper())
except ConnectionResetError as e:
print("%s %s" % (client_addr[0],client_addr[1]),e)
# 如果对方下线了 那服务器也应该关闭对应的客户端对象
client_socket.close()
break


# 通常服务器不会关闭
# server.close()

客户端.py
import socket

client = socket.socket()
# 指定服务器的端口和ip 客户端的端口系统自动分配的
client.connect(("127.0.0.1",8989)) #


# 添加循环 用来重复收发数据
while True:
# 收发的顺序 必须很对面相反 否则卡死了
msg = input("输入内容:")
if not msg:continue
client.send(msg.encode("utf-8"))
print("sended!")
data = client.recv(1024)
print(data.decode("utf-8"))


client.close()
1.6window正常结束

服务器.py
import socket
server = socket.socket()
server.bind(("127.0.0.1",8989))
server.listen()

while True:
client_socket,client_addr = server.accept()
buffer_size = 1024 #缓冲区  就是一个临时的容器  
# 缓冲区大小 不能随便写 太大会导致内存溢出 太小效率低 在内存能够承受的情况下 大一些

while True:
try:
data = client_socket.recv(1024)
# 在linux中 对方如果强行下线了 服务器不会抛出异常 只会收到空消息
# 得加上判断 如果为空则意味着 对方下线了 应该关闭链接 跳出循环
if not data:
client_socket.close()
break

print("收到数据:",data.decode("utf-8")) # 解码时必须保证双方同意编码方式
# 转为大写在发回去
client_socket.send(data.upper())
except ConnectionResetError as e:
print("%s %s" % (client_addr[0],client_addr[1]),e)
# 如果对方下线了 那服务器也应该关闭对应的客户端对象
client_socket.close()
break


# 通常服务器不会关闭
# server.close()

客户端.py
import socket

client = socket.socket()
# 指定服务器的端口和ip 客户端的端口系统自动分配的
client.connect(("127.0.0.1",8989)) #


# 添加循环 用来重复收发数据
while True:
# 收发的顺序 必须很对面相反 否则卡死了
msg = input("输入内容:(q:退出)")
if msg == "q":break
if not msg:continue
client.send(msg.encode("utf-8"))
print("sended!")
data = client.recv(1024)
print(data.decode("utf-8"))

client.close()
 
​ 
 
 
 
 
 
 
 
 
 
 
​  
​ 
​ 
​ 
    ​ 
   
   
    ​ 
    ​ 
   
   
   
   
   
    
   
   
   
   
   
    ​ 
    ​ 
   
    ​ 
   
   
   
   
   
   
       
    ​ 
   
    ​ 
   
   
   
   
   
   
   
   
   
   
   
   
   
    ​ 
    ​ 
   
   
   
   
   
   
   
   
   
   
 
 
​ 
​ 
 
 
 
 
 
​  
 
 
 
​ 
 
 
 
 
 
 
 
 
 
原文地址:https://www.cnblogs.com/llx--20190411/p/10937340.html