初始socket模块和巧解粘包问题

1.什么是socket?

  两个进程如果需要进行通讯最基本的一个前提能够唯一的标示一个进程,在本地进程通讯中我们可以使用PID来唯一标示一个进程,但PID只在本地唯一,网络中的两个进程PID冲突几率很大,这时候我们需要另辟它径了,我们知道IP层的ip地址可以唯一标示主机,而TCP层协议和端口号可以唯一标示主机的一个进程,这样我们可以利用ip地址+协议+端口号唯一标示网络中的一个进程。

  能够唯一标示网络中的进程后,它们就可以利用socket进行通信了,什么是socket呢?我们经常把socket翻译为套接字,socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信。

  socket是应用层与TCP/IP协议族通信的中间软件层,它是一组接口。在设计模式中,socket其实就是一个门面模式,它把复杂的TCP/IP协议隐藏在socket接口后面,对用户来说,一组简单的接口就是全部,让socket去组织数据,以符合之id那个的协议。

  所以,我们无需深入理解TCP/UDP协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,那么写出的程序自然是符合TCP/UDP标准的。

2.套接字的种类

  我们认识的套接字分为两种:1)基于文件的套接字:AF_UNIX

                2) 基于协议的套接字:AF_INET

  unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一台机器上可以通过访问同一个文件系统间接完成通信。但是,AF_INET是使用最为广泛的一个,python支持多种地址家族,但是我们只关心网络编程,所以大部分我们只是用AF_INET。

3.套接字的使用

1)基本使用

import socket# 买手机 默认得到是一个TCP的socket
server = socket.socket()server.bind(("127.0.0.1",16888))  # 绑定手机卡

server.listen() # 开始待机# 得到对方的socket对象与地址
client,addr = server.accept() # 接收通话请求 # 该函数会阻塞 直到有连接请求过来# buffersize 表示应用程序的缓冲区大小     recv其实是 从系统缓冲区读取数据到应用程序
data = client.recv(1024)   # 该函数会阻塞 直到操作缓冲区有数据位置print("收到客户端发来的数据:%s" % data.decode("utf-8"))# 发生的数据必须为bytes类型
client.send(data)
client.close() #挂断电话
server.close() # 关机
服务器
import socketclient = socket.socket()client.connect(("127.0.0.1",16888))client.send("hello 服务器".encode("utf-8"))data = client.recv(1024)   # 该函数会阻塞 直到操作缓冲区有数据位置print("收到服务器:%s" % data.decode("utf-8"))client.close()
客户端

2)通信循环

import socket
server=socket.socket()
server.bind(("127.0.0.1",16888))
# 开始待机
server.listen()# 通信循环
while True:client,addr=server.accept()while True:try:# 如果是windows 对方强行关闭连接会抛出异常# 如果是linux 不会抛出异常 会收到空的数据包进入死循环data=client.recv(1024)if not data :client.close()breakprint('收到数据%s:'%data.decode('utf-8'))client.send(data)except ConnectionResetError:print('客户端关闭连接')client.close()break
# 挂断电话
client.close()
# 关机
server.close()
服务端
import socket
client=socket.socket()
client.connect(("127.0.0.1",16888))
while True:msg=input('>>>:')client.send(msg.encode('utf-8'))data=client.recv(1024)print('收到服务器:%s'%data.decode('utf-8'))
client.close()
客户端

3)TCP协议的异常处理

import  socketserver = socket.socket()server.bind(("127.0.0.1",8888))server.listen()client,addr = server.accept()while True:try:data = client.recv(1024)if not data:print("对方已经关闭.....")breakprint(data.decode("utf-8"))client.send(data.upper())except ConnectionResetError:print("对方异常关闭连接...")client.close()
server.close()
服务端
import  socketclient = socket.socket()
client.connect(("127.0.0.1",8888))client.send("hello".encode("utf-8"))data = client.recv(1024)
print(data.decode("utf-8"))client.close()
客户端

4.粘包问题(处理方式)

   粘包产生的原因:1.对于数据接受端来说,它不知道自己接受的将会是多大的数据。

          2.对于发送方来说,TCP内部会将很小的数据都打包在一起,一起发送。

粘包的解决方案:(以操作shell指令为例)

 

import socket, subprocess
import json
import structIP_PORT = ('127.0.0.1', 8888)
server = socket.socket()
server.bind(IP_PORT)
server.listen(5)while True:conn, addr = server.accept()while True:try:data = conn.recv(1024).decode('utf-8')if len(data) == 0: breakobj = subprocess.Popen(data, shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)stdout = obj.stdout.read()stderr = obj.stderr.read()info_dic = {'name': '二进制指令','len': len(stdout + stderr)}info_bytes = json.dumps(info_dic).encode('utf-8')header = struct.pack('i', len(info_bytes))conn.send(header)conn.send(info_bytes)conn.send(stderr + stdout)except ConnectionResetError:breakconn.close()
服务端

 

import socket
import struct
import jsonIP_PORT = ('127.0.0.1', 8888)
cilent = socket.socket()
cilent.connect(IP_PORT)while True:cmd = input('cmd>>>>')if len(cmd) == 0: continuecilent.send(cmd.encode('utf-8'))header = cilent.recv(4)header_len = struct.unpack('i', header)[0]info_dic = json.loads(cilent.recv(header_len).decode('utf-8'))total_size = info_dic.get('len')rec_size = 0res = b''while rec_size < total_size:data = cilent.recv(1024)res += datarec_size += len(data)print(res.decode('gbk'))
客户端

5.案列:客户端传送大文件

 

import socket
import json
import structIP_PORT = ('127.0.0.1', 9633)
server = socket.socket()
server.bind(IP_PORT)
server.listen(5)while True:conn, addr = server.accept()while True:try:# 接收报头header = conn.recv(4)# 解包得到字典的真实长度file_bytes = struct.unpack('i',header)[0]# 反序列化成字典file_info = json.loads(conn.recv(file_bytes).decode('utf-8'))file_name = file_info.get('file_name')file_size = file_info.get('file_size')rec_size = 0# 开始接受文件,并写入with open(file_name, 'wb') as w:while rec_size < file_size:data = conn.recv(1024)w.write(data)rec_size += len(data)print(file_info.get('msg'))except ConnectionResetError:breakconn.close()
server

 

import socket
import json
import struct
import osIP_PORT = ('127.0.0.1', 9633)
cilent = socket.socket()
cilent.connect(IP_PORT)# 文件的大小
file_size = os.path.getsize(r'E:\fullstack_s4\day32\3.标记删除.mp4')
# 文件的名字
file_name = "王鹏是小猪.mp4"
# 定义文件信息字典
file_info = {'file_name': file_name,'file_size ': file_size,'msg': "不要老师看?会被影响的!"
}
# 将字典序列化为二进制
header_bytes = json.dumps(file_info).encode('utf-8')
# 打包并生报头
header = struct.pack('i', len(header_bytes))
# 发送报头
cilent.send(header)
# 发送报头字典
cilent.send(header_bytes)
# 发送真实的数据
with open(r'E:\fullstack_s4\day32\3.标记删除.mp4', 'rb') as f:for line in f:cilent.send(line)
cilent

6.UDP协议

  UDP协议属于数据报协议,没有双向通道的存在。

  相比TCP协议: 1.他不会存在粘包问题

          2.客户端可以发空

         3.看似是并发过程

         4.在不启动服务短的情况下,运行客户端不会报错

 

import socketIP_PORT = ('127.0.0.1', 8080)
server = socket.socket(socket.SOCK_DGRAM)
server.bind(IP_PORT)while True:conn, addr = server.recvfrom(1024)print(conn, addr)server.sendto(conn.upper(), addr)
UDPserver

 

import socketIP_PORT = ('127.0.0.1', 8080)
cilent = socket.socket(socket.SOCK_DGRAM)cilent.sendto(b'hello baby',IP_PORT)
UDPcilent

 

7.socketserver模块

 

import socketserverclass MyServer(socketserver.BaseRequestHandler):def handle(self):while True:data = self.request.recv(1024)print(data)self.request.send(data.upper())if __name__ == '__main__':server = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyServer)server.serve_forever()
服务端

 

import socketcilent = socket.socket()
cilent.connect(('127.0.0.1',8080))while True:cilent.send(b'hello')data = cilent.recv(1024)print(data)
客户端

 

转载于:https://www.cnblogs.com/wanglei957/p/10806350.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/362861.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

100325 雨

回家以后怎么样&#xff1f; 感冒没有严重吧&#xff1f; 你也多喝水 我好些了 鼻涕不像昨天那么多了 就是嗓子疼 药吃了 喝了不少水了转载于:https://www.cnblogs.com/loverain/archive/2010/03/25/1694567.html

Java的挥发性修饰符

不久前&#xff0c;我编写了一个Java servlet过滤器&#xff0c;该过滤器在其init函数中加载配置&#xff08;基于web.xml的参数&#xff09;。 筛选器的配置缓存在私有字段中。 我在字段上设置了volatile修饰符。 后来&#xff0c;当我检查Sonar公司以查看是否在代码中发现任…

webpack常用loader和plugin及打包速度优化

优化 或 也可以用&#xff1a; 备用&#xff1a; 慎用的配置&#xff0c;用的不好会增加打包时间&#xff1a; 代码丑化插件&#xff1a; 更多专业前端知识&#xff0c;请上 【猿2048】www.mk2048.com

nvl 函数

nvl(oie.is_eval,N) <> Y 理解成 oie.is_eval <> Y 转载于:https://www.cnblogs.com/wangchuanfu/p/10818274.html

在自定义HttpHandler中如何使用Session

今天我写了一段程序在HttpHandler中使用Session。结果Session对象报错&#xff0c;“未将对象引用设置到对象的实例”&#xff0c;我郁闷半天&#xff0c;不知道怎么回事。结果我google了一下&#xff0c;原来也有人碰到过这种情况哦。呵呵。网上也有很多人说出了这些问题。解决…

SSH登录太慢(等很久才提示输入密码)的问题

SSH登录太慢(等很久才提示输入密码)的问题 SSH 登录太慢可能是 DNS 解析的问题&#xff0c;默认配置下 sshd 初次接受 ssh 客户端连接的时候会自动反向解析客户端 IP 以得到 ssh 客户端的域名或主机名。 如果这个时候 DNS 的反向解析不正确&#xff0c;sshd 就会等到 DNS 解析超…

开发Eclipse插件

最近&#xff0c;我开始与团队合作开发Eclipse插件。 团队开发了一个很棒的插件&#xff0c;可以实现预期的目的。 因此&#xff0c;我签出了源并尝试构建它。 项目源包含所有必需的库&#xff0c;并且只能在Eclipse中构建。 在当今不断交付的世界中&#xff0c;这是一个主要障…

react-native 热更新react-native-pushy集成遇到的问题

主要步骤按官方文档实现&#xff0c;这里只记录遇到的一些小坑 官方文档 run-android时NDK报错 前提是NDK已安装并且环境变量已设置 根据报错提示在 android/local.properties文件里加入ndk.dir~/Library/Android/android-ndk-r10e //这里改成你自己的ndk路径 cxxbridge找…

[转]在资源管理器中使鼠标右键增加一个命令,运行cmd,同时使得当前路径为资源管理器当前的目录...

[转]在资源管理器中使鼠标右键增加一个命令&#xff0c;运行cmd&#xff0c;同时使得当前路径为资源管理器当前的目录 http://www.cnblogs.com/skywind/archive/2009/05/22/1487138.html 1,找开注册表编辑器&#xff1b; 2,找到HKEY_CLASSES_ROOT\Folder\shell&#xff1b; 3,在…

Keil5 仿真测试出现Cannot Load Flash Device Description 解决方法

1.用ST的烧录软件检测&#xff0c;可以烧录对应的Hex文件。 2.点击魔术棒&#xff0c;Debug选项卡检测芯片型号是否和当前芯片对应 3.在Flash Download选项卡中检查发现没有对应的芯片型号 4.点击Add 选项&#xff0c;选择对应的Flash类型如图&#xff1a; 添加Flash类型后&…

Spring,REST,Ajax和CORS

假设您正在为客户端开发基于JavaScript的项目&#xff0c;并且他通过其余的Web服务向服务器发出Ajax请求&#xff0c;那么您可能会遇到一些麻烦&#xff0c;尤其是如果双方都在单独的域中。 实际上&#xff0c;出于安全原因&#xff0c;未授权从一个域A到另一域B的Ajax请求。 …

位运算实现加减乘除四则运算(Java)

本文是继《一文了解有趣的位运算》的第二篇文章. 我们知道&#xff0c;计算机最基本的操作单元是字节(byte)&#xff0c;一个字节由8个位(bit)组成&#xff0c;一个位只能存储一个0或1&#xff0c;其实也就是高低电平。无论多么复杂的逻辑、庞大的数据、酷炫的界面&#xff0c;…

消息(6)——WCF,构建简单的WCF服务,MTOM编码

构建一个简单的WCF服务。以Web服务类似的步骤由IIS进行宿主服务。建立的步骤&#xff1a;1 新建3.5网站2 添加WCF服务&#xff0c;自动生成契约接口与实现&#xff0c;这里改动一下&#xff0c;添加个字串参数&#xff1a;[ServiceContract]public interface IFirstService{[Op…

Hadoop—MapReducer统计文件的单词出现的个数

1. MapReduce 统计文件的单词出现的个数 Mapper: 处理具体文本&#xff0c;发送结果 Reducer: 合并各个Mapper发送过来的结果 Job: 制定相关配置&#xff0c;框架 Mapper package cn.itcast.hadoop.mr.wordcount;import java.io.IOException;import org.apache.hadoop.io.LongW…

从框架到平台

当我将近十年前作为Java开发人员开始我的职业生涯时&#xff0c;该行业正在经历革命性的变化。 Spring框架&#xff08;于2003年发布&#xff09;Swift发展起来&#xff0c;并成为庞大的J2EE平台的严重挑战者。 经过过渡时间后&#xff0c;我很快发现自己赞成使用Spring框架而不…

关于setTimeout和setInterval的函数参数问题

今天在写验证码倒计时小demo时&#xff0c;用了如下代码&#xff1a; window.setTimeout(count(num),1000);这样直接使用将使count函数立即执行&#xff0c;并将返回值传递给setTimeout函数作为参数&#xff0c;其结果并不是真正需要的&#xff0c;所以会出现问题。 方法一 …

课堂作业2

1、动手动脑 阅读示例: EnumTest.java&#xff0c;运行它&#xff0c;分析运行结果&#xff1f;你能得到什么结论&#xff1f;你掌握了枚举类型的基本用法了吗&#xff1f; public class EnumTest {public static void main(String[] args) {Size sSize.SMALL;Size tSize.LARGE…

(转)详解Vs2008下打包安装程序的一些技巧(含win7下提权限、卸载以及安装时定向到网页)...

1、怎么使得程序窗口左上角和任务栏有图标&#xff0c;如下图所示&#xff1a; 其实这个问题不应该放到程序打包这部分讲&#xff0c;只不过对于一些初学者而言&#xff0c;在这提下也许会有很大的帮助&#xff08;想到自己刚学.net那会了&#xff0c;呵呵&#xff09;。方法之…

复合双重错误

总览 在上一篇文章中&#xff0c;我概述了为什么BigDecimal大部分时间都不是答案。 虽然可以构造double会产生错误的情况&#xff0c;但在BigDecimal遇到错误的情况下构造情况也一样容易。 BigDecimal更容易正确&#xff0c;但更容易出错。 轶事证据表明&#xff0c;初级开发人…

vue入门学习示例

鄙人一直是用angular框架的&#xff0c;所以顺便比较了一下。 1 <!DOCTYPE html>2 <html lang"en">3 <head>4 <meta charset"UTF-8">5 <title>vue实践</title>6 <script src"http://cdn.bootcss.…