socket套接字

1、什么是socket

socket是一个模块,又称套接字,用来封装互联网协议(应用层以下的层)

2、为什么要有socket

实现应用层以下的层的工作,提高开发效率

3、怎么使用socket

先导入socket模块,先启动服务端套接字,再启动客户端套接字

# 服务端

import socket
# 买手机
server = socket.socket()
# 绑定手机号(IP,port)
# IP单机模式是127.0.0.1,局域网内使用cmd中ipconfig查询IPV4
# port设置8000以后的数据
server.bind(('127.0.0.1', 9876))
# 设置半连接池
server.listen(4)
# 可接收多个客户端数据连接,实现循环通信
while True:
# 接收客户端连接
conn, addr = server.accept()
# 查看对方地址
print(addr)
while True:
# 捕获异常机制
try:
# 接收客户端发来的数据,可一次接收1024bytes的数据
data = conn.recv(1024)
if len(date) == 0:
break
if data.decode('utf-8') == 'q':
break
print(data.decode('utf-8'))
# 向客户端发送消息
send_data = input('请输入向客户端发送的数据:')
conn.send(send_data.encode('utf-8'))
# 捕获异常,并打印出错误信息
except Exception as e:
print(e)
break
# 挂电话
conn.close()
# 客户端

import socket
# 买手机
client = socket.socket()
# 建立连接(IP,port)
client.connect(('127.0.0.1',9876))
while True:
try:
# 向对方发送数据
data = input('请输入向服务端发送的数据')
client.send((data.encode('utf--8')))
# 接收对方发来的数据可设置一次接收的bytes数,并打印
res_data = client.recv(1024)
if len(res_data) == 0:
break
if res_data.decode('utf-8') == 'q':
break
print(res_data.decode('utf-8'))
# 捕获异常,并打印出异常
except Exception as e:
print(e)
break
client.close()

粘包问题

问题1:

无法确认对方发送过来数据大小

问题2:

在发送数据间隔短并且数据量小的情况下,会将所有数据一次性发送

解决:需要确认对方发送的数据大小

# 客户端
# 问题1
import socket
client = socket.socket()
client.connect(('127.0.0.1', 9876))
while True:
try:
cmd = input('请输入向服务端发送的命令:')
client.send(cmd.encode('utf-8'))
# 接收服务端返回的数据
# 由于不知道会返回多少个bytes所以有问题1
date = client.recv(11910)
print(len(date))
print(date.decode('gbk'))
except Exception as e:
print(e)
break
client.close()
# 客户端
# 问题2
# 时间间隔短,并数据量小的情况下,会将所有的数据一次性发送,接收时不知道具体有几个
import socket
client = socket.socket()
client.connect(('127.0.0.1', 9876))
client.send(b'hello')
client.send(b'hello')
client.send(b'hello')
client.send(b'hello')
client.send(b'hello')
# 服务端

import socket
import subprocess server = socket.socket()
server.bind(('127.0.0.1', 9876))
server.listen(4)
while True:
conn, addr = server.accept()
print(addr) while True:
try:
# 接收客户端的数据,具体值不知道多大,所有有可能不能完全接收,有可能浪费资源
cmd = conn.recv(12)
if len(cmd) == 0:
break
cmd = cmd.decode('utf-8')
if cmd == 'q':
break
# 调用subprocess连接终端,对终端进行操作,并获取正确和错误的结果
obj = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# 拿到结果,并打印
result = obj.stdout.read() + obj.stderr.read()
print(result.decode('gbk'))
# 将结果返回给客户端
conn.send(result) except Exception as e:
print(e)
break
conn.close()

解决粘包问题

使用struct模块

struct 是一个python内置的模块,它可以将固定长度的数据,打包成固定格式的长度

模式:i:4,或其他模式

作用:将真实数据做成一个固定长度的报头,发送给服务端,服务端接收报头,然后进行解包,获取真实数据的长度,进行接收数据即可

import struct
data = input('请输入传的数据').strip()
data = data.encode('utf-8')
# 制作报头,需要 i 的字符串和传入数据的长度
header = struct.pack('i',len(data))
print(header)
print(len(header)) # 解包( i 的字符串和报头)获取真实长度,得到一个元组,拿到元组第一个数就是真实长度
res = struct.unpack('i', header)[0]
print(res) # utf-8中一个中文是3个bytes,一个英文是1个bytes

客户端:

​ 1.先制作报头,并发送

​ 2.发送真实数据

服务端:

​ 1.接收报头,并且解包获取真实数据长度

​ 2.根据真实数据长度,接收真实数据

# 客户端
import socket
import struct client = socket.socket()
client.connect(('127.0.0.1', 9876))
while True:
try:
cmd = input('请输入向服务端发送的命令')
cmd_bytes = cmd.encode('utf-8')
# 做一个报头
header = struct.pack('i', len(cmd_bytes))
# 发送报头
client.send(header)
# 发送真实数据
client.send(cmd_bytes)
# 接受服务端返回的报头
reheader = client.recv(4)
# 解包
data_len = struct.unpack('i', reheader)[0]
result = client.recv(data_len)
print(result.decode('gbk'))
except Exception as e:
print(e)
break
client.close()
# 服务端
import socket
import subprocess
import struct server = socket.socket()
server.bind(('127.0.0.1', 9876))
server.listen(5)
while True:
conn, addr = server.accept()
while True:
try:
# 获取报头
header = conn.recv(4)
# 获取真实数据长度
data_len = struct.unpack('i', header)[0]
# 准备接受真实数据
cmd = conn.recv(data_len)
cmd = cmd.decode('utf-8')
if cmd == 'q':
break
if len(cmd) == 0:
break
obj = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
result = obj.stdout.read() + obj.stderr.read()
print(len(result))
print(result.decode('gbk'))
# 将结果返回给客户端
header = struct.pack('i', len(result))
conn.send(header)
conn.send(result)
except Exception as e:
print(e)
break
conn.close()
# 客户端
import socket
import struct
import json
client = socket.socket()
client.connect(('127.0.0.1', 9876))
while True:
# 伪装电影数据
movie_name = input('请输入电影名称:')
movie_len = 10000101
send_dic = {
'movie_name': movie_name,
'movie_len': movie_len
}
# 序列化
json_data = json.dumps(send_dic)
# 制作报头
json_bytes = json_data.encode('utf-8')
header = struct.pack('i', len(json_bytes))
# 发送报头
client.send(header)
# 发送真实数据
client.send(json_bytes)
# 服务端
import socket
import json
import struct server = socket.socket()
server.bind(('127.0.0.1', 9876))
server.listen(5)
while True:
conn, addr = server.accept()
print(addr)
while True:
try:
# 接收报头
header = conn.recv(4)
# 解包获取真实长度
json_len = struct.unpack('i', header)[0]
# 接收真实长度
json_bytes_data = conn.recv(json_len)
json_data = json_bytes_data.decode('utf-8')
# 反序列化得到数据
back_dic = json.loads(json_data)
print(back_dic)
except Exception as e:
print(e)
break
conn.close()

最新文章

  1. 提交本地项目到github服务器
  2. python导入模块和包的使用
  3. ajax验证登录注册
  4. Ubuntu jsp平台使用JDBC来连接MySQL数据库
  5. javascript中字符串格式json如何转化成json对象
  6. JAVA ,SSH中文及其乱码问题的解决 6大配置点 使用UTF-8编码
  7. D3学习教程
  8. 减小Delphi的Exe文件大小(11种方法)
  9. gradle项目与maven项目相互转化(转)
  10. struts2.1.6教程五、拦截器
  11. JQuery上传插件Uploadify详解及其中文按钮解决方案 .
  12. 第6次结对作业--郑锦伟&古维城
  13. C++ STL中的map用红黑树实现,搜索效率是O(lgN),为什么不像python一样用散列表从而获得常数级搜索效率呢?
  14. IIS7启动优化
  15. mybatis基础系列(四)——关联查询、延迟加载、一级缓存与二级缓存
  16. 700. Search in a Binary Search Tree
  17. Qt5设置应用程序图标
  18. MSSQL-SQL SERVER一些使用中的技巧
  19. Kafka Consumer接口
  20. 如何在CentOS 7中禁用IPv6

热门文章

  1. 关于App收集个人信息基本规范,这里公开征求你的意见!
  2. Visual Studio 调试系列7 查看变量占用的内存(使用内存窗口)
  3. 5行代码带你实现一个js的打字效果
  4. ElasticSearch如何更新集群的状态
  5. Mysql load data infile 命令格式
  6. MarkDown的一些基本语法
  7. linux服务器可以访问IP访问不了域名地址
  8. python练习题:利用切片操作,实现一个trim()函数,去除字符串首尾的空格,注意不要调用str的strip()方法
  9. wcf序列化嵌套类(如TreeNode)异常原因
  10. 基于YOLO3对图像加框的函数draw_image()