今日内容

  • socket 套接字编程

    • 简易服务端与客户端代码实现
  • 通信循环
  • 黏包现象(TCP协议)
  • 报头制作、struct 模块、封装形式

内容详细

一、socket 套接字编程

实现一款能够进行数据交互的程序。

他们互通信息就得通过网络传输数据,那就肯定会涉及 OSI 七层协议的操作,而每次传输数据都要对OSI 七层协议进行操作,就会重复很多相似的工作,这时候就出现了 socket 模块,封装了OSI 七层协议的操作代码,我们在传输数据时,就可以通过socket 实例化的对象以点的形式方便快捷调用操作方法。

  • socket 模块

下面,我就用 socket 模块实现一个最简易的套接字编程

注意:先有服务端启动,客户端才能够成功连接服务端,实现数据互通

服务端

import socket

# 实例化一个套接字对象
server = socket.socket() # 给'服务端(应用程序)'绑定一个 IP + 端口号,作为唯一标识
server.bind(('192.168.11.134', 8080)) # 设置半连接池,最多容量(等待连接数)为5
server.listen(5) # 监听,当有客户端申请连接,获取它的socket对象和应用程序地址(IP+端口)
sock, address = server.accept() # 接收数据
data = sock.recv(1024) print(data.decode('utf8')) # 发送数据
sock.send('elijah is very good'.encode('utf8')) # 关闭与客户端连接的socket对象
sock.close() # 关闭服务端自己的socket对象
server.close()

客户端

import socket

# 实例化客户端的socket对象
client = socket.socket() # 客户端根据 IP+端口 精准连接服务端
client.connect(('192.168.11.134', 8080)) # 给服务端发送数据
client.send('i am client'.encode('utf8')) # 接收服务端回传的数据
data = client.recv(1024) print(data.decode('utf8')) # 关闭客户端
client.close()

二、通信循环

给简易版本升一下级,让服务端与客户端可以输入自定义的信息,并且不会一传输完数据就结束进程,让服务端一直处于监听状态,随时可以与客户端进行连接。

服务端

import socket

# 实例化一个套接字对象
server = socket.socket() # 给'服务端(应用程序)'绑定一个 IP + 端口号,作为唯一标识
server.bind(('192.168.11.134', 8080)) # 设置半连接池,最多容量(等待连接数)为5
server.listen(5) # 监听,当有客户端申请连接,获取它的socket对象和应用程序地址(IP+端口)
sock, address = server.accept() while True:
# 接收数据
client_data = sock.recv(1024) print(client_data.decode('utf8')) # 发送数据
server_data = input('输入您的回复>>>: ')
sock.send(server_data.encode('utf8'))

客户端

import socket

# 实例化客户端的socket对象
client = socket.socket() # 客户端根据 IP+端口 精准连接服务端
client.connect(('192.168.11.134', 8080)) while True:
# 给服务端发送数据
client_data = input('输入您的信息>>>: ')
client.send(client_data.encode('utf8')) # 接收服务端回传的数据
data = client.recv(1024) print(data.decode('utf8'))

实现你一句我一句的通信:

代码优化

1、让服务端一直处于监听状态,当服务端回复空消息,则断开与当前客户端的连接,回到监听状态
2、客户端发送的消息不可以为空(避免两者都处于revc等待状态)
3、服务端添加兼容性代码(mac linux)
4、服务端重启频繁报端口占用错误
from socket import SOL_SOCKET, SO_REUSEADDR
server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # 在bind前加
5、客户端异常关闭服务端报错的问题
异常捕获 6.服务端链接循环
7.半连接池
设置可以等待的客户端数量(超出数量会报错)

服务端

import socket

# 实例化一个套接字对象
server = socket.socket() # 给'服务端(应用程序)'绑定一个 IP + 端口号,作为唯一标识
server.bind(('192.168.11.134', 8080)) # 设置半连接池,最多容量(等待连接数)为5
server.listen(5) while True:
# 监听,当有客户端申请连接,获取它的socket对象和应用程序地址(IP+端口)
sock, address = server.accept() while True:
# 处理客户端异常断开错误
try:
# 接收数据
client_data = sock.recv(1024) print(client_data.decode('utf8')) # 发送数据
server_data = input('输入您的回复>>>: ')
if len(server_data) == 0:
break
sock.send(server_data.encode('utf8'))
except Exception as e:
print(e)
break

客户端

import socket

# 实例化客户端的socket对象
client = socket.socket() # 客户端根据 IP+端口 精准连接服务端
client.connect(('192.168.11.134', 8080)) while True:
# 给服务端发送数据
client_msg = input('输入您的信息>>>: ')
if len(client_msg) == 0:
continue
client.send(client_msg.encode('utf8')) # 接收服务端回传的数据
data = client.recv(1024) print(data.decode('utf8'))

三、黏包问题

由于TCP协议也是一个流式协议,数据是会像流水一样进行传输

当客户端向服务端发起命令请求,服务端返回很大容量的数据,而客户端一次只接收1024字节,显然接收不完,剩余的数据不会丢失,而是会堵在传输通道中,等客户端下一次发起申请命令时,剩余的数据就会涌入,导致答非所问的问题。

TCP协议有一个特性

当发送的数据量比较少,多次发送,且发送时间间隔比较短
那么TCP会自动把这些数据全部打包成一个数据包接收 sock.send('litle')
sock.send('ll')
sock.send('a') client.recv()
client.recv()
client.recv()
---》 litlella

解决黏包问题

  • 制作报头

报头用于标识即将到来的数据具体信息

比如,数据的具体大小,这样,接收方就可以根据这个数据大小的具体信息,决定接收多大的数据

client.recv(4343534)

简易版本报头

import socket
import subprocess
import json
import struct server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5) while True:
sock, address = server.accept()
while True:
data = sock.recv(1024) # 接收cmd命令
command_cmd = data.decode('utf8')
sub = subprocess.Popen(command_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
res = sub.stdout.read() + sub.stderr.read() # 结果可能很大
# 1.制作报头
data_first = struct.pack('i', len(res))
# 2.发送报头
sock.send(data_first)
# 3.发送真实数据
sock.send(res) import socket
import struct client = socket.socket() # 买手机
client.connect(('127.0.0.1', 8080)) # 拨号 while True:
msg = input('请输入cmd命令>>>:').strip()
if len(msg) == 0:
continue
client.send(msg.encode('utf8'))
# 1.先接收固定长度为4的报头数据
recv_first = client.recv(4)
# 2.解析报头
real_length = struct.unpack('i',recv_first)[0]
# 3.接收真实数据
real_data = client.recv(real_length)
print(real_data.decode('gbk'))

可以把报头制作成字典的形式,这样,除了可以接收数据具体大小信息,还可以接收更多其它的数据信息,并且strut 打包时 'i' 模式也不会数据过大而报错

拓展知识

在阅读源码的时候
1.变量名后面跟冒号 表示的意思是该变量名需要指代的数据类型
2.函数后更横杆加大于号表示的意思是该函数的返回值类型

socket 套接字编程的更多相关文章

  1. linux网络环境下socket套接字编程(UDP文件传输)

    今天我们来介绍一下在linux网络环境下使用socket套接字实现两个进程下文件的上传,下载,和退出操作! 在socket套接字编程中,我们当然可以基于TCP的传输协议来进行传输,但是在文件的传输中, ...

  2. linux网络编程-(socket套接字编程UDP传输)

    今天我们来介绍一下在linux网络环境下使用socket套接字实现两个进程下文件的上传,下载,和退出操作! 在socket套接字编程中,我们当然可以基于TCP的传输协议来进行传输,但是在文件的传输中, ...

  3. socket套接字编程 HTTP协议

    socket套接字编程  套接字介绍  1. 套接字 : 实现网络编程进行数据传输的一种技术手段  2. Python实现套接字编程:import  socket  3. 套接字分类 >流式套接 ...

  4. Linux之socket套接字编程20160704

    介绍套接字之前,我们先看一下传输层的协议TCP与UDP: TCP协议与UDP协议的区别 首先咱们弄清楚,TCP协议和UCP协议与TCP/IP协议的联系,很多人犯糊涂了,一直都是说TCP/IP协议与UD ...

  5. 基于TCP协议的socket套接字编程

    目录 一.什么是Scoket 二.套接字发展史及分类 2.1 基于文件类型的套接字家族 2.2 基于网络类型的套接字家族 三.套接字工作流程 3.1 服务端套接字函数 3.2 客户端套接字函数 3.3 ...

  6. 基于TCP连接的socket套接字编程

    基于TCP协议的套接字编程(简单) 服务端 import socket server = socket.socket() server.bind( ('127.0.0.1', 9999) ) serv ...

  7. day31 socket套接字编程

    为什么要有套接字编程? 在上节课的学习中,我们学习了OSI七层协议,但是如果每次进行编程时我们都需要一层一层的将各种协议使用在我们的程序中,这样编写程序实在是太麻烦了,所以为了让程序的编写更加的简单, ...

  8. socket套接字编程(1)——基本函数

    TCP交互流程: 服务器:1. 创建socket:2. 绑定socket和端口号:3. 监听端口号:4. 接收来自客户端的连接请求:5. 从socket中读取字符:6. 关闭socket. 客户端:1 ...

  9. 19、网络编程 (Socket套接字编程)

    网络模型 *A:网络模型 TCP/IP协议中的四层分别是应用层.传输层.网络层和链路层,每层分别负责不同的通信功能,接下来针对这四层进行详细地讲解. 链路层:链路层是用于定义物理传输通道,通常是对某些 ...

随机推荐

  1. 查询 Oralce 某 schema 所拥有的权限

    --https://dba.stackexchange.com/questions/14901/oracle-list-users-with-access-to-certain-tables sele ...

  2. (随手记)Javascript 的parseInt函数,在IE和非IE内核浏览器运行的不同结果

    一段JS小程序: var str = "09"; var itr = parseInt(str); alert(itr); IE下运行,alert(0); 火狐和chrome下运行 ...

  3. SpringBoot学习笔记三之表述层

    注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6803355920697917965/ 首先配置learn-admin-webui中的web.xml文件 配置Con ...

  4. Python网络编程之网络基础

    Python网络编程之网络基础 目录 Python网络编程之网络基础 1. 计算机网络发展 1.1. OSI七层模型 1.2. 七层模型传输数据过程 2. TCP/IP协议栈 2.1 TCP/IP和O ...

  5. 学习javaScript必知必会(3)~数组(数组创建,for...in遍历,辅助函数,高级函数filter、map、reduce)

    一.数组: 1.js是弱语言,js中的数组定义时:不用指定数据类型.不用功指定数组长度:数组可以存储任何数据类型的数据 2.数组定义的[ ] 的实质: [] = new Array(); {} = n ...

  6. leetcode 120. 三角形最小路径和 及 53. 最大子序和

    三角形最小路径和 问题描述 给定一个三角形,找出自顶向下的最小路径和.每一步只能移动到下一行中相邻的结点上. 例如,给定三角形: [ [2], [3,4], [6,5,7], [4,1,8,3] ] ...

  7. JDK原子操作类

    在Atomic包里一共提供了13个类,属于4种类型的原子更新方式,分别是原子更新基本类型.原子更新数组.原子更新引用和原子更新属性(字段).Atomic包里的类基本都是使用Unsafe实现的包装类. ...

  8. Windows如何搭建SSL通信(非Web)

    自己研究了会儿,把结论发出来给有需要的人 第一步:准备环境 首先需要一台服务器(这不是废话吗),我这边用的windows2003, 还需要一台客户端,我用的是windwos2008 第二步:服务器环境 ...

  9. .Net Api 之如何使用Elasticsearch存储文档

    .Net Api 之如何使用Elasticsearch存储文档 什么是Elasticsearch? Elasticsearch 是一个分布式.高扩展.高实时的搜索与数据分析引擎.它能很方便的使大量数据 ...

  10. Dapr 和 Azure Functions : Hello world

    本篇文章内容来自 https://charliedigital.com/2021/07/01/dapr-and-azure-functions-part-1-hello-world/ ,是按这篇文章的 ...