python-网络编程

1.osi五层协议

# 应用层
    # 传输层
        # tcp协议 : 效率低 面向连接\可靠\全双工的通信
            # 三次握手
                # 客户端向服务器端发送syn请求,
                # 服务端向客户端回复ack并发送syn请求,
                # 客户端接收到请求之后再回复ack表示建立连接
                # 由客户端的connect + 服务端的accept
            # 四次挥手
                # 客户端向服务端发送fin请求,
                # 服务端回复ack确认
                # 服务端向客户端发送fin请求,
                # 客户端回复ack确认
                # 有客户端的close和服务端的close
        # udp协议 : 效率高 无连接的\不可靠
        # 四层交换机 四层路由器
    # 网络层
        # ip协议(ipv4 ipv6)
        # 路由器\三层交换机
    # 数据链路层
        # arp协议 地址解析协议 通过ip找到mac地址
        # 交换机\网卡 : 单播 广播 组播
    # 物理层

2  b/s c/s架构

 C/S   client server
 B/S   browser server

 

3.tcp协议和udp协议

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

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

我知道说这些你们也不懂,直接上图。

 

3.简单的tcp网络通信

#server服务端

import socket  #炒茄子

sk = socket.socket()          # 创建一个server端的对象
sk.bind(('127.0.0.1',9001))  # 给server端绑定一个地址 ,可以写自己的IP地址
sk.listen()                   # 开始监听(可以接收)客户端给我的连接了

conn,addr = sk.accept()  # 建立连接 conn是连接,ADDR是地址,也可以不写这个变量
conn.send(b'hello')   #联上后,进行通信
msg = conn.recv(1024) #1024 表示最多接收1024个字
print(msg)
conn.close()     # 关闭连接

sk.close()  #关掉服务
client客户端
import socket

sk = socket.socket()   #实例化对象
sk.connect(('127.0.0.1',9001))  #联接server端


msg = sk.recv(1024)   #1024 表示最多接收1024个字
print(msg)
sk.send(b'byebye')

sk.close()

 5.tcp简单多人通信

#server端

import socket
sk = socket.socket()
sk.bind(('127.0.0.1',9001))   # 申请操作系统的资源
sk.listen()

while True:  # 为了和多个客户端进行握手
    conn,addr = sk.accept() # 能够和多个客户端进行握手了
    print('conn : ',conn)
    while True:
        send_msg = input('>>>')
        conn.send(send_msg.encode('utf-8'))
        if send_msg.upper() == 'Q':
            break
        msg = conn.recv(1024).decode('utf-8')
        if msg.upper() == 'Q': break
        print(msg)
    conn.close()    # 挥手 断开连接

sk.close()      # 归还申请的操作系统的资源
#client

# _*_ coding : UTF-8 _*_
import socket
sk = socket.socket()
sk.connect(('127.0.0.1',9001))


while True:
    msg = sk.recv(1024)  #����
    msg2 = msg.decode('utf-8')
    if msg2.upper() == 'Q':break
    print(msg,msg2)
    send_msg = input('>>>')
    sk.send(send_msg.encode('utf-8'))
    if send_msg.upper() == 'Q':
            break
sk.close()

6.简单的udp协议

#server

import socket
sk = socket.socket(type= socket.SOCK_DGRAM)

sk.bind(('127.0.0.1',9000))

msg,addr = sk.recvfrom(1024)
print(msg)

sk.sendto(b'2',addr)
# client

import  socket
sk = socket.socket(type=socket.SOCK_DGRAM)

server = ('127.0.0.1',9000)

sk.sendto(b'1',server)

msg = sk.recv(1024)
print(msg)

7.多人的udp协议

#server

import socket
#udp可以跟任意人联接.
sk = socket.socket(type = socket.SOCK_DGRAM) #udp协议  实例化对象
sk.bind(('127.0.0.1',9001))   #联接
while True:
    msg,addr= sk.recvfrom(1024)  #接收
    print(msg.decode('utf-8'))
    msg = input('>>>')
    sk.sendto(msg.encode('utf-8'),addr)  #发送


#server不能接收Q退出..不然就不能跟别人联接了..只需要客户端退出就行了
#client

import socket

sk = socket.socket(type=socket.SOCK_DGRAM)
server = ('127.0.0.1',9001)
while True:
    msg = input('>>>')
    if msg.upper() == 'Q':break
    sk.sendto(msg.encode('utf-8'),server)   # 发送
    msg = sk.recv(1024).decode('utf-8')  #收到
    if msg.upper() == 'Q':break
    print(msg)

 8.黏包    struct 模块

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

 

import struct

num1 = 129469649
num2 = 123
num3 = 8

ret1 = struct.pack('i',num1) #把一个整数pack
print(len(ret1))
ret2 = struct.pack('i',num2)
print(len(ret2))
ret3 = struct.pack('i',num3)
print(len(ret3))

print(struct.unpack('i',ret1))  #转为原来数值129469649
print(struct.unpack('i', ret2))
print(struct.unpack('i', ret3))

 

8.1 tcp协议的现象

#server端

import struct
import socket

sk = socket.socket()
sk.bind(('127.0.0.1',9001))
sk.listen()

conn,addr = sk.accept()
msg1 = input('>>>').encode()
msg2 = input('>>>').encode()
# num = str()  # '10001'
# ret = num.zfill(4)    # '0006' 补0.向左补4个0
# conn.send(ret.encode('utf-8'))
blen = struct.pack('i',len(msg1))
conn.send(blen)
conn.send(msg1)
conn.send(msg2)
conn.close()
sk.close()

# 粘包现象
# 只出现在tcp协议中,因为tcp协议 多条消息之间没有边界,并且还有一大堆优化算法
# 发送端 : 两条消息都很短,发送的间隔时间也非常短
# 接收端 : 多条消息由于没有及时接收,而在接收方的缓存短堆在一起导致的粘包

# 解决粘包问题的本质 :设置边界


# server端
# 1.先计算要发送的数据的长度
# 通过struct模块把长度转换成固定的4字节
# 发送4个字节的长度
# 发送内容....
#client端

import time
import struct
import socket

sk = socket.socket()
sk.connect(('127.0.0.1',9001))
# length = int(sk.recv(4).decode('utf-8'))
length = sk.recv(4)
length = struct.unpack('i',length)[0] #返回的是元组
msg1 = sk.recv(length)
msg2 = sk.recv(1024)
print(msg1.decode('utf-8'))
print(msg2.decode('utf-8'))

sk.close()

 

 9.基于udp 协议的多人聊天  自动识别用户,

 

server端

import socket
friend ={'小明':34,'小王':32}
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind(('127.0.0.1',9000))

while True:
    mag,addr = sk.recvfrom(1024)

    mag = (mag.decode('utf-8'))
    name,message = mag.split('|')
    print('\033[1;%sm;%s:%s\033[0m'%(friend.get(name,30),name,message))

    mag = input('<<<')
    sk.sendto(mag.encode('utf-8'),addr)
client端

import  socket
name = '小明'

while True:
    sk = socket.socket(type=socket.SOCK_DGRAM)
    server = (('127.0.0.1',9000))

    mag = input('<<<')
    if mag.upper() =='Q':break
    mag = '%s|%s'%(name,mag)
    sk.sendto(mag.encode('utf-8'),server)
    mag = sk.recv(1024).decode('utf-8')
    if mag.upper() == 'Q': break
    print(mag)

 

 10.用tcp实现接收发送小文件和大文件的功能

servet端
#接收

import  socket
import  json
import struct

sk = socket.socket()
# sk.bind(('127.0.0.1'),9000)
sk.bind(('127.0.0.1',7003))
sk.listen()

conn,addr = sk.accept()
#为了解决粘包现象,先接收4个字节.
# mag = conn.recv(1024).decode('utf-8')
mag = conn.recv(4)
dic_len = struct.unpack('i',mag)[0]
dic_len = conn.recv(dic_len).decode('utf-8')

mag = json.loads(dic_len)

with open(mag['filename'],mode='wb') as f:
    while mag['filesize'] > 0:
        content = conn.recv(1024) #先接1024字节
        mag['filesize'] -= len(content)  #在接剩余的

        f.write(content)

conn.close()
sk.close()
client端

mport  socket
import json
import os
import struct
sk = socket.socket()
sk.connect(('127.0.0.1',7003))

#文件/文件名
addr_path = r'E:\zl\day07 课上视频\day07 课上视频\04 python fullstack s22 day07 编码的进阶【it资源社区www.it0365.com】.mp4'
filename = os.path.basename(addr_path) #文件
filesize = os.path.getsize(addr_path)  #文件大小
dic = {'filename':filename,'filesize':filesize}
new_mag =json.dumps(dic)  #json传字符串
new_mag = new_mag.encode('utf-8')
mlab = struct.pack('i',len(new_mag))
sk.send(mlab)   ## 4个字节 表示字典转成字节之后的长度
sk.send(new_mag)  ## 具体的字典数据



#如要传大文件的话.需要减去大小
#还有为了防止粘包..
with open(addr_path,mode='rb') as f:
    while filesize>0:
        content = f.read(1024) #先读1024个字节
        filesize -= len(content)  #总字节减去传送过去的
        sk.send(content)

sk.close()

 

 11.检验客户端的合法性

server端

import  os
import socket
import hashlib


secket_key = b'zeng'

sk = socket.socket()
# sk.bind(('127.0.0.1',9001))
sk.bind(('127.0.0.1',7005))
sk.listen()

conn,addr = sk.accept()

# 创建一个随机的字符串
ret = os.urandom(32)

# 发送随机字符串
conn.send(ret)

# 根据发送的字符串 + secrete key 进行摘要
sha = hashlib.sha1(secket_key)
sha.update(ret)
res = sha.hexdigest()  #获取密文
# 等待接收客户端的摘要结果
res_new = conn.recv(1024).decode('utf-8')
# 做比对
if res_new == res:
    print('合法的')
   # 如果一致,就显示是合法的客户端
    # 并可以继续操作
    conn.send(b'ok')
else:
    conn.close()
    # 如果不一致,应立即关闭连接
client端


import socket
import hashlib

secket_key = b'zeng'


sk = socket.socket()
# sk.connect(('127.0.0.1',9001))
sk.connect(('127.0.0.1',7001))



# 接收客户端发送的随机字符串
ret = sk.recv(32)

# 根据发送的字符串 + secret key 进行摘要
sha=hashlib.sha1(secket_key)  #密钥
sha.update(ret)  #发送
res = sha.hexdigest()  #获取密文

# 摘要结果发送回server端
sk.send(res.encode('utf-8'))
# 继续和server端进行通信
mag = sk.recv(1024)
print(mag)

 

 12.socketserver  ,后续所有的server端.都用这模块.需要记住这代码.client端不变

 

以后用tcp时.需要建立目录.目录为socketserver .在此目录下,还需要建立server和client
#server

import socketserver
import time

class Myserver(socketserver.BaseRequestHandler):
    def handle(self):

        conn = self.request

        while True:
            try:
                content = conn.recv(1024).decode('utf-8')
                conn.send(content.upper().encode('utf-8'))
                time.sleep(1)
            except ConnectionRefusedError:
                break



server = socketserver.ThreadingTCPServer(('127.0.0.1',7004),Myserver)
server.serve_forever()
#client

import socket

sk=socket.socket()
sk.connect(('127.0.0.1',7004))

while True:

    sk.send(b'hehe')
    mag = sk.recv(1024).decode('utf-8')
    print(con,mag)

 


posted @ 2020-05-10 08:58  水晶冰洛  阅读(157)  评论(0编辑  收藏  举报