1  复习

2  TCP-UDP协议

3  tcp协议的socket

4  复杂tcp协议的socket

5  带退出的聊天程序

6  时间练习demo

7  粘包现象

1.复习

# 网络编程概念
# 两大开发架构
# C/S B/S

# ip地址
# mac地址
# 内网/外网
# 交换机 : 单播、广播、组播
# 在一个局域网内的通信
# 二层/数据链路层 - osi七层协议
# 数据链路层的协议 :arp协议(通过一台机器的ip地址找到mac地址)
# 数据链路层的网络设备 : 交换机、网卡
# 路由器 :
# 局域网与局域网之间的连接工具
# 三层/网络层 - osi七层协议
# 网络层的协议 :ip协议
# 网络层的设备 :路由器、三层交换机
# 网关
# 一个局域网要想访问局域网外部的其他机器,都要通过统一的网关接口
# 子网掩码
# 判断两台机器是否在同一个局域网内
# 端口来定位某一台机器上的某一个服务
# 如何定位你的网络中能够找到的唯一一台机器+服务 ip + 该服务的端口号

2.tcp-udp协议

# osi七层协议的传输层 : TCP/UDP协议
# 这两个协议标志着我们的数据传递的方式
# tcp协议 :语音通话
# 必须先接通电话,同一时刻只能和一个人聊天,传输比较稳定,慢
# 可以发送任意长度的消息
# udp协议 :发微信
# 不需要接通 只要互相知道ip 端口就可以通信 ,同时可以和多个人聊天,但是传输相对不稳定,传输速度快
# 不能传输过长的消息

# tcp :发送文件(邮件)、下载安装包、上传、下载电影、从网盘上上传、下载文件
# udp :即时通信类的、在线播放

# tcp协议
# 为什么它传输稳定、可靠?
# 先建立连接
# 三次握手、四次挥手
# tcp协议和udp协议各自的特点

3  tcp协议的socket

server

import socket  #套接字

sk = socket.socket()  #先买一部手机sk.bind(('127.0.0.1',9600))  #绑定一个电话卡  PS本地回环地址127.0.0.1sk.listen()  #开机  py3.4后()里可以不加数字conn,addr = sk.accept()  #阻塞,直到有客户端来连接,三次握手建立连接print(addr)  # ('127.0.0.1', 52171)print(conn)  # 包含addr的一些信息print(sk)    # 不包含addr的conn信息conn.send(b'hello')msg = conn.recv(1024)print(msg)conn.close()  #四次挥手,断开连接sk.close()  #关机

client

import socket

sk = socket.socket()sk.connect(('127.0.0.1',9600))msg = sk.recv(1024)print(msg)sk.send(b'byebye')sk.close()

4  复杂tcp协议的socket

    PS:连续相互对话

server

sk = socket.socket()sk.bind(('127.0.0.1',9600))sk.listen()conn,addr = sk.accept()  #conn,addr只是可以换其他代替

while True:    send_msg = input('msg : ')    conn.send(send_msg.encode())    msg = conn.recv(1024).decode()    print(msg)conn.close()sk.close()

client

import socket

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

while True:    msg = sk.recv(1024).decode()    print(msg)    send_msg = input('msg : ')    sk.send(send_msg.encode())

sk.close()

5  带退出的聊天程序

server

import socket

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

conn,addr = sk.accept()

while True:    send_msg = input('msg : ')   # q    conn.send(send_msg.encode()) # send(q)    if send_msg == 'q':break    msg = conn.recv(1024).decode()    if msg == 'q':break    print(msg)

conn.close()

client

import socket

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

while True:    msg = sk.recv(1024).decode()    if msg == 'q':break    print(msg)    send_msg = input('msg : ')    sk.send(send_msg.encode())    if send_msg == 'q':break

sk.close()

6  时间练习demo

server

import socketimport time

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

while True:    conn,addr = sk.accept()    fmt = conn.recv(1024)    str_time = time.strftime(fmt.decode())    conn.send(str_time.encode())    conn.close()sk.close()

client

import socket

sk = socket.socket()sk.connect(('127.0.0.1',9600))sk.send(b'%Y/%m/%d %H:%M:%S')msg = sk.recv(1024).decode()print(msg)sk.close()

补充:

# str 字符串数据类型
# bytes 字节数据类型
# 中 :gbk bytes 100100110101
# 中 :utf8 bytes 100111100001
# send(bytes)
# bytes = recv()
# 我们要看 是看str
# 我们在发送数据之前是str,发送的是bytes
# 就需要对str进行编码,str.encode('utf-8')结果是一个bytes
# 我们在接受数据的时候 收到的也是bytes类型
# 我们要想看懂必须把bytes解码,bytes.decode('utf-8')结果就是一个字符串

7  粘包现象

server

import struct
import socket

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

conn,addr = sk.accept()
send_msg = input('>>>').encode()
bytes_len = struct.pack('i',len(send_msg))
conn.send(bytes_len)
conn.send(send_msg) # 粘包现象
conn.send(b'world')
conn.close()
sk.close()

# 1.发送端的粘包 合包机制 + 缓存区
# 2.接收端的粘包 延迟接受 + 缓存区
# 3.流式传输
# 电流 高低电压
# 所以我们说 tcp协议是无边界的流式传输
# 4.拆包机制

# 粘包现象
# 接收端不知道发送端给我发送了多长的数据

client

import struct
import socket

sk = socket.socket()
sk.connect(('127.0.0.1',9000))
bytes_len = sk.recv(4)
msg_len = struct.unpack('i',bytes_len)[0]
msg = sk.recv(msg_len)
print(msg.decode())
msg2 = sk.recv(5)
print(msg2)
sk.close()

解决方法一

import struct

ret = struct.pack('i',560000)
print(ret,len(ret))
ret1 = struct.pack('i',123)
print(ret1,len(ret1))
ret2 = struct.pack('i',902730757)
print(ret2,len(ret2))

res = struct.unpack('i',ret)
print(res[0])
res = struct.unpack('i',ret1)
print(res[0])
res = struct.unpack('i',ret2)
print(res[0])

day24_python_1124的更多相关文章

随机推荐

  1. jdbc之工具类DBUtil的使用

    首先回顾一下jdbc的使用方法: 1. 注册驱动 2. 建立连接 3. 建立statement 4. 定义sql语句 5. 执行sql语句,如果执行的是查询需遍历结果集 6. 关闭连接 其中建立连接和 ...

  2. C# RSA加解密与验签,AES加解密,以及与JAVA平台的密文加解密

    前言: RSA算法是利用公钥与密钥对数据进行加密验证的一种算法.一般是拿私钥对数据进行签名,公钥发给友商,将数据及签名一同发给友商,友商利用公钥对签名进行验证.也可以使用公钥对数据加密,然后用私钥对数 ...

  3. AOP之proceedingjoinpoint和joinpoint区别(获取各对象备忘)、动态代理机制及获取原理代理对象、获取Mybatis Mapper接口原始对象

    现在AOP的场景越来越多,所以我们有必要理解下和AOP相关的一些概念和机制. import org.aspectj.lang.reflect.SourceLocation; public interf ...

  4. NOIP 2018 划水记

    (此处不应有目录) (本来想咕掉这篇游记) Day -1 今天信心题,这个毒瘤出题人怎么出了一堆垃圾题(smallfat批判这个垃圾题). T2,T3是送分题.T1考了个noip根本不会考得类欧几里德 ...

  5. Redis集群 - Sentinel与RAFT算法

    引入   在主从模型中讲到 一旦Master宕机失效,需要手动将Slave角色提升为Master,否则这个子集群将不可用.   这个缺陷使得系统可用性大大降低.因此Redis专门提供了一个哨兵机制来实 ...

  6. 【HNOI 2016】序列

    Problem Description 给定长度为 \(n\) 的序列:\(a_1, a_2, \cdots , a_n\),记为 \(a[1 \colon n]\).类似地,\(a[l \colon ...

  7. hibernate 一对多关系中的孤儿属性

    @OneToMany(targetEntity = BenefitType.class, mappedBy = "sitePerson",cascade = CascadeType ...

  8. /etc/security/limits.conf不生效

    总结下来发现要使limits.conf生效,需要在  /etc/ssh/sshd_config  配置中 设置 UsePAM  yes UseLogin yes    #这个保证其他的用户也能修改设置 ...

  9. js for 循环示例

    //for 循环 ,,,,,,]; ; i < array.length; i++) { console.log(i,array[i]); } //for in ,,,,,,]; for(let ...

  10. loadrunner 参数化取值方式详解

    参数化对话框中与参数取值方式有关的区域如下: 改变参数化的取值方式,关键在于Select next row和Update value on这两个选项. Select next row包括以下选项: S ...