客户端/服务器的架构

物理层:网卡,光缆,双绞线

数据链路层:包含源mac地址和目标的mac地址,通过广播通讯

网络层:跑的IP协议,IP地址可以定义到一个子网;通过ARP协议可以解析为mac地址;

传输层:提供端口 0-65535 TCP/UDP基于端口传输的

====》socket抽象层{抽象一堆接口,只要遵循socket标准,就支持TCP/UDP基于端口传输}

应用层:软件

客户端与服务端的连接:

1.服务端连接关键字注释:

import socket

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 基于网络通信,是TCP协议的通讯
server.bind(("127.0.0.1", 8080)) # 开启 绑定IP以及端口
server.listen(5) # 监听;进程池的大小5 # conn 三次握手建立的连接, addr 客户端地址 端口
conn, addr = server.accept()
print("TCP 的链接", conn)
print("客户端的地址和端口", addr) # conn.recv 接收消息;1024 代表接收到 1024个字节 (二进制格式) secv
data = conn.recv(1024)
print("来自于客户端的消息: %s" % data) # 打印输出内容 # 发消息 给 客户端 send (将接收的消息转换为大写返回给客户端 二进制)
conn.send(data.upper()) conn.close() # 关闭连接
server.close() # 结束套接字

2.客户端连接关键字注释:

import socket

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 基于网络通信,是TCP协议的通讯
client.connect(("127.0.0.1", 8080)) # 与服务端进行连接;
client.send("Hello".encode("utf-8")) # 客户端发消息给 服务端 send 需要二进制 encode # 客户端收取 服务端发过来的消息
data = client.recv(1024)
print("来自于服务端的数据:%s" % data) client.close() # 关闭客户端

输出内容:

# 服务端内容:
TCP 的链接 <socket.socket fd=284, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 61799)>
客户端的地址和端口 ('127.0.0.1', 61799)
来自于客户端的消息: b'Hello' # 客户端内容:
来自于服务端的数据:b'HELLO'

解决粘包问题:

1.服务端解决粘包问题:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2017/3/4 import socket
import subprocess # 远程执行命令模块
import struct server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 基于网络通信,是TCP协议的通讯
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 重用ip和端口,在绑定IP 端口之前 bind 之前
server.bind(("127.0.0.1", 8080)) # 开启 绑定IP以及端口
server.listen(5) # 监听;进程池的大小5 while True: # 循环连接 循环
# conn 三次握手建立的连接, addr 客户端地址 端口
conn, addr = server.accept()
print("客户端地址:", addr) while True: # 消息传输 循环
# conn.recv 接收消息;1024 代表接收到 1024个字节 (二进制格式) secv try: # 捕捉异常
cmd = conn.recv(1024) # recv 会导致堵塞 if not cmd:
break # 针对Linux 客户端断开后 进入死循环现象; print("来自于客户端的消息: %s" % cmd) # 打印输出内容
# 发消息 给 客户端 send (将接收的消息转换为大写返回给客户端 二进制) res = subprocess.Popen(cmd.decode("utf-8"), # 使用 utf-8 解码
shell=True, # 使用shell 解析
stdout=subprocess.PIPE, # 标准输出定向到 管道
stderr=subprocess.PIPE) # 标准错误输出 定向到 管道 err = res.stderr.read()
if err:
back_msg = err
else:
back_msg = res.stdout.read() #####解决粘包部分#####
conn.send(struct.pack("i", len(back_msg))) # 计算出 返回值的长度
conn.sendall(back_msg) # sendall将数据循环的返回 将得到的数据 输出返回
#####↑↑↑↑↑↑↑↑↑↑↑##### except Exception: # 如果发现 异常,直接break
break conn.close() # 关闭连接
server.close() # 结束套接字

2.客户端解决粘包问题

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2017/3/4 import socket
import struct client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 基于网络通信,是TCP协议的通讯 client.connect(("127.0.0.1", 8080)) # 与服务端进行连接; while True:
cmd = input("输入你的命令:").strip()
if not cmd:
continue client.send(cmd.encode("utf-8"))
#####解决粘包部分#####
data = client.recv(4)
data_size = struct.unpack("i", data)[0] recv_size = 0 # 收取数据的尺寸
recv_bytes = b"" # 收到的bytes 用于拼接
while recv_size < data_size:
res = client.recv(1024) recv_bytes += res
recv_size += len(res)
#####↑↑↑↑↑↑↑↑↑↑↑##### print(recv_bytes.decode("gbk"))

当返回值过大时,通过自定义报头方式解决粘包

1.自定义报头,发送方服务端配置

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2017/3/4 import socket
import subprocess # 远程执行命令模块
import struct
import json server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 基于网络通信,是TCP协议的通讯
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 重用ip和端口,在绑定IP 端口之前 bind 之前
server.bind(("127.0.0.1", 8080)) # 开启 绑定IP以及端口
server.listen(5) # 监听;进程池的大小5 while True: # 循环连接 循环
# conn 三次握手建立的连接, addr 客户端地址 端口
conn, addr = server.accept()
print("客户端地址:", addr) while True: # 消息传输 循环
# conn.recv 接收消息;1024 代表接收到 1024个字节 (二进制格式) secv try: # 捕捉异常
cmd = conn.recv(1024) # recv 会导致堵塞 if not cmd:
break # 针对Linux 客户端断开后 进入死循环现象; print("来自于客户端的消息: %s" % cmd) # 打印输出内容
# 发消息 给 客户端 send (将接收的消息转换为大写返回给客户端 二进制) res = subprocess.Popen(cmd.decode("utf-8"), # 使用 utf-8 解码
shell=True, # 使用shell 解析
stdout=subprocess.PIPE, # 标准输出定向到 管道
stderr=subprocess.PIPE) # 标准错误输出 定向到 管道 err = res.stderr.read()
if err:
back_msg = err
else:
back_msg = res.stdout.read()
# ########将返回长度记录到字典当中,分三次将所有数据发出
# 制作字典
head_dic = {
"data_size": len(back_msg)
} head_json = json.dumps(head_dic) # 将字典依照 json 格式存储
head_bytes = head_json.encode("utf-8") # 将json 格式 解码为 二进制bytes格式 conn.send(struct.pack("i", len(head_bytes))) # 第一次发:将计算的报头head_bytes长度发送给客户端
conn.send(head_bytes) # 第二次发:发送报头的数据 conn.sendall(back_msg) # 第三次发:sendall将数据循环的返回 将得到的数据 输出返回 except Exception: # 如果发现 异常,直接break
break
# ######↑↑↑↑↑↑↑↑↑↑↑↑↑ conn.close() # 关闭连接
server.close() # 结束套接字

2.自定义报头,接收客户端配置

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2017/3/4 import socket
import struct
import json client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 基于网络通信,是TCP协议的通讯
client.connect(("127.0.0.1", 8080)) # 与服务端进行连接; while True:
cmd = input("输入你的命令:").strip()
if not cmd:
continue client.send(cmd.encode("utf-8")) # 收取 服务端返回的数据:分三次收取
# 1.收报头的长度
head = client.recv(4) # 收取报头 二进制格式"b'\x11\x00\x00\x00'"
head_size = struct.unpack("i", head)[0] # 取出报头长度 int "17" # 2.收报头:根据报头的长度
head_bytes = client.recv(head_size) # 根据报头长度head_size 收取报头 二进制格式"b'{"data_size": 61}'"
head_json = head_bytes.decode("utf-8") # 将bytes的格式解码为 json的字符串 "'str'{"data_size": 61}" head_dic = json.loads(head_json) # 将json字符串转换为 字典 "'dict'{'data_size': 61}"
data_size = head_dic["data_size"] # 取出真实数据的长度 "61" # 3.根据长度-收取真实数据
recv_size = 0 # 收取数据的尺寸
recv_bytes = b"" # 收到的bytes 用于拼接
while recv_size < data_size:
res = client.recv(1024) recv_bytes += res
recv_size += len(res)
print(recv_bytes.decode("gbk"))

010-Python-socket编程的更多相关文章

  1. Python Socket 编程——聊天室示例程序

    上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和客户端的代码了解基本的 Python Socket 编程模型.本文再通过一个例子来加强一下对 Socket 编程的 ...

  2. python/socket编程之粘包

    python/socket编程之粘包 粘包 只有TCP有粘包现象,UDP永远不会粘包. 首先需要掌握一个socket收发消息的原理 发送端可以是1k,1k的发送数据而接受端的应用程序可以2k,2k的提 ...

  3. PYTHON SOCKET编程简介

    原文地址: PYTHON SOCKET编程详细介绍   Python 提供了两个基本的 socket 模块. 第一个是 Socket,它提供了标准的 BSD Sockets API. 第二个是 Soc ...

  4. python socket编程笔记

    用python实现一个简单的socket网络聊天通讯 (Linux --py2.7平台与windows--py3.6平台) 人生苦短之我用Python篇(socket编程) python之路 sock ...

  5. [Python_7] Python Socket 编程

    0. 说明 Python Socket 编程 1. TCP 协议 [TCP Server] 通过 netstat -ano 查看端口是否开启 # -*-coding:utf-8-*- "&q ...

  6. Python Socket 编程示例 Echo Server

    简评:我们已经从「Python Socket 编程概览」了解了 socket API 的概述以及客户端和服务器的通信方式,接下来让我们创建第一个客户端和服务器,我们将从一个简单的实现开始,服务器将简单 ...

  7. Python Socket 编程——聊天室演示样例程序

    上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和client的代码了解主要的 Python Socket 编程模型.本文再通过一个样例来加强一下对 Socket ...

  8. python socket编程入门(编写server实例)+send 与sendall的区别与使用方法

    python 编写server的步骤: 1. 第一步是创建socket对象.调用socket构造函数.如: socket = socket.socket( family, type ) family参 ...

  9. 第九章:Python高级编程-Python socket编程

    第九章:Python高级编程-Python socket编程 Python3高级核心技术97讲 笔记 9.1 弄懂HTTP.Socket.TCP这几个概念 Socket为我们封装好了协议 9.2 cl ...

  10. python socket编程详细介绍

    Python 提供了两个基本的 socket 模块. 第一个是 Socket,它提供了标准的 BSD Sockets API. 第二个是 SocketServer, 它提供了服务器中心类,可以简化网络 ...

随机推荐

  1. SpringSecurity项目中如何在多个模块中配置认证信息

    ⒈在SpringSecurity项目中创建AuthorizeConfigProvider接口用于配置认证信息 package cn.coreqi.ssoserver.authorize; import ...

  2. Node.js的异步IO和事件轮询

     想象一下,以前我们在写程序时, 如果程序在I/O上阻塞了,当有更多请求过来时,服务器会怎么处理呢?在这种情景中通常会用多线程的方式.一种常见的实现是给每个连接分配一个线程,并为那些连接设置一个线程池 ...

  3. a标签中href属性引起的页面不跳转问题

    先简单描述问题,今天在做一个简单的提交页面的时候,碰到了跳转不了的问题.其中a标签的形式<a href="" onclick="submit()"> ...

  4. jQuery中如何实现多库并存?

    多库共存就是“$ ”符号的冲突. 方法一: 利用jQuery的实用函数$.noConflict();这个函数归还$的名称控制权给另一个库,因此可以在页面上使用其他库.这时,我们可以用"jQu ...

  5. 025_lua脚本语言

    一.--cat /opt/nginx/conf/conf.dlua_package_path '/opt/nginx/conf/lua/?.lua;;'; --lua模块路径,其中”;;”表示默认搜索 ...

  6. VI和VIM

    linux下vi.VIM命令大全   进入vi的命令 vi filename :打开或新建文件,并将光标置于第一行首 vi +n filename :打开文件,并将光标置于第n行首 vi + file ...

  7. Appium新版本不再支持ByName定位了怎么办

    appium版本在1.5以后就不再支持ByName的定位,本文章仅介绍在appium1.6.3/1.6.4/1.6.5版本下如何支持ByName定位,适用于安卓.在使用appium1.5之后的版本时, ...

  8. 自动化工具 Sikuli-Script 使用

    Sikuli-IDE用起来方便,但是用到实际项目中还是有局限性的,Sikuli提供了Sikuli-Script的jar包,在Sikuli-X的安装目录下,这样就可以在 eclipse中使用JAVA编写 ...

  9. jquery中的attr与prop的区别,什么时候用attr,什么时候用prop

    只要有 Boolean() 属性的,简单说就是具有true 和 false 两个属性的属性,如 checked, selected 或者 disabled 使用prop(),(其实这些都是表单类的), ...

  10. swiper轮播图(逆向自动切换类似于无限循环)

    swiper插件轮播图,默认的轮播循序是会从右向左,第一张,第二张,第三张,然后肉眼可见是的从第三张从左到右倒回第一张,这样就会有些视觉体验不高, ,不过还是能够用swiper本身的特性更改成无限循环 ...