首页 > 编程语言 >改写socket编程并解释socket通信原理

改写socket编程并解释socket通信原理

时间:2024-08-08 15:54:52浏览次数:8  
标签:socket 编程 tcp server 改写 内存 服务端 客户端

如果你仔细看我之前的博客,会看到那个手机打电话的示例,但是那段代码彻底写死了,真正编程的时候一定要写活了,不信你看看很多的程序的配置文件就是这样的,为什么单独分离个配置文件出来,就是为了便于修改配置,这就是把程序写活的最好的例子。

言归正传,直接上代码。

服务端:
from socket import *
ip_port=('127.0.0.1',8080)
backlog=5
buffer_size=1024

tcp_server=socket(AF_INET,SOCK_STREAM)
tcp_server.bind(ip_port)
tcp_server.listen(backlog)
conn,addr=tcp_server.accept()
data=conn.recv(buffer_size)
print('客户端发来的消息是:',data.decode('utf-8'))
conn.send(data.upper())
conn.close()
tcp_server.close()
输出结果:
客户端发送的消息是: hello

客户端:
from socket import *
ip_port=('127.0.0.1',8080)
msg='hello'
buffer_size=1024

tcp_client=socket(AF_INET,SOCK_STREAM)
tcp_client.connect(ip_port)
tcp_client.send(msg.encode('utf-8'))
data=tcp_client.recv(buffer_size)
print('服务端发来的消息是:',data.decode('utf-8'))
tcp_client.close()
输出结果:
服务端发来的消息是: HELLO

其中,
from socket import *
ip_port=('127.0.0.1',8080)
backlog=5
buffer_size=1024
这一段可以单独提出来放到另外一个配置文件中。

上面这段代码还是不够好,你想一想,难道服务端和客户端之间就通信一次就结束了吗?显示是不对的,那么应该写个循环,改下代码如下:

服务端:
from socket import *
ip_port=('127.0.0.1',8080)
backlog=5
buffer_size=1024

tcp_server=socket(AF_INET,SOCK_STREAM)
tcp_server.bind(ip_port)
tcp_server.listen(backlog)
conn,addr=tcp_server.accept()
while True:
    data=conn.recv(buffer_size)
    print('客户端发来的消息是:',data.decode('utf-8'))
    conn.send(data.upper())
conn.close()
tcp_server.close()

客户端:
from socket import *
ip_port=('127.0.0.1',8080)
buffer_size=1024

tcp_client=socket(AF_INET,SOCK_STREAM)
tcp_client.connect(ip_port)
while True:
    msg=input('你要发送给服务端的内容是:')
    tcp_client.send(msg.encode('utf-8'))
    data=tcp_client.recv(buffer_size)
    print('服务端发来的消息是:',data.decode('utf-8'))
tcp_client.close()

上面这段代码如果客户端发送一个空(直接回车),就会导致客户端和服务端都卡住,你可知道是为什么?按道理说不应该是客户端发送什么,服务端就会收到什么吗?其实不是这样的,下面我就来讲一下这个客户端和服务端通信的原理:

如上图所示,
其实计算机主要的组件可以分为三层,最上层是应用软件,中间层是OS也就是操作系统,最底层是硬件(如网卡等硬件)。
从上图可以看出服务端和客户端之间的传输并非是直接就传过去了,启动一个应用程序,实际上是把该应用程序加载到内存中然后才启动的。内存分为用户态内存和内核态内存。应用程序启动时被加载到了用户态内存中,所谓内核态内存就是操作系统运行所在的内存区域。
下面我们来分析,为什么在发送空的时候,客户端和服务端会卡住,实际步骤如下:

1> 客户端向服务端发送一个空请求,该请求会从用户态内存发送到客户端自身的内核态内存(涉及到一系列封包操作,最后发出去的只能是字节形式)
注意: 正常非空请求会从内核态内存发送到服务端,之后到达服务端的内核态内存中,最后socket服务端程序再从内存中把消息取出来。
2> 因为是空请求,客户端内核态内存中的消息并不会被传输到服务端,也就意味着服务端的内核态内存中啥也没有。
3> socket服务端应用程序从用户态内存读取内核态内存里的消息,此时显示是读不到的,因为压根就没有,所以就一直处于等待状态。
4> 因为服务端没有收到消息,自然也没办法给客户端返回消息,所以客户端也会一直处于等待状态,从来两边都是卡死状态了。

以上就是客户端和服务端之间通信的真正原理,搞明白这个很重要,这就是我一直强调的对待知识一定要知其然且知其所以然。
继续借此平台阐发我的哲学思想,学习任何知识其实是有方法的,简而化之就是三步:
第一步:输入知识
第二步:理解消化
第三步:灵活运用
记住我的话,读书是学习,看视频课程是学习,生活处处是学习,但还有个最重要的学习叫做运用。

标签:socket,编程,tcp,server,改写,内存,服务端,客户端
From: https://www.cnblogs.com/kkbest/p/18348266

相关文章

  • LangChain与泛型编程:探索代码生成的新维度
    LangChain与泛型编程:探索代码生成的新维度在软件开发领域,泛型编程是一种允许创建可重用组件的技术,这些组件可以在多种数据类型上工作的编程范式。LangChain作为一个假设的编程辅助工具,如果存在,它可能会支持泛型编程,以增强其代码生成的能力。本文将探讨LangChain对泛型编程......
  • 网络编程
    本篇文章目的为编程后期的互联网项目做铺垫只为对开发涉及到的网络知识进行入门了解网络概述计算机网络:计算机网络(连接分散计算机设备以实现信息传递的系统)锁定计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,......
  • 编程思维的养成
    引言编程思维(ComputationalThinking)是一种解决问题的方式,通过将问题分解为可处理的部分,使用算法和逻辑进行解决。它不仅适用于计算机科学领域,也能在日常生活和其他学科中发挥作用。培养编程思维对提高逻辑思维能力、解决问题的效率和创新能力具有重要意义。本文将探讨编程思......
  • AOP切面编程
    AOP切面编程一些知识切面:处理共同逻辑的模块@Aspect 用在类上,表示这个类是一个切面目标:被切面作用的业务模块切入点:用于指定那些切面作用于哪些目标组件上,一般用表达式实现。通知:切面和切入点的执行循序;分为:前置通知,后置通知,最终通知,环绕通知,异常通知前置通知(BeforeAdvic......
  • Spring AOP:面向切面编程的最佳实践 ( 一 )
    1.AOP思想1.1.为什么需要面向切面编程如果在一个类或者多个类的多个业务逻辑方法中,在开始,结尾部分包含功能相同的代码称之为横切关注点也叫切面,这种结构可能符合传统的面向对象编程(OOP)的封装特性,但可能导致代码难以维护和扩展。面向切面编程是一种编程范式。它允......
  • 系统编程 days4 文件3
    前提:函数fileno(FILE*stream)作用:获得一个文件流指针的文件描述符,为了将FILE*fp型转化为intfd型函数fdopen(intfd,constchar*mode)intfd型转化为FILE*fp型文件属性目录顺序:1.打开目标目录2.读取目录3.关闭目录打开目录函数opendir获得一个目录流指针,返回值为Dir*=d......
  • 趣味Python游戏编程:第3章 递归函数的威力:扫雷
    趣味Python游戏编程:第3章递归函数的威力:扫雷在第2章中,我们制作了一个拼图游戏,玩家通过鼠标操作图片块移动。本章设计一款扫雷游戏,玩法是在一个方块阵列中随机埋设一定数量的地雷,然后由玩家逐个打开方块,并以排除所有地雷为最终游戏目标。如果玩家打开的方块中有地雷,则游戏......
  • Java的网络编程?
    Java的网络编程涉及使用Java的API来创建和管理网络应用程序,例如客户端和服务器之间的通信。Java提供了一系列的类和接口来支持网络编程,主要包括java.net包中的功能。网络编程通常包括以下几个方面:Java网络编程的基本概念协议:TCP/IP(传输控制协议/网际协议):一种面向......
  • linux 软件编程学习第八天 线程
    进程1.waitpid   pid_twaitpid(pid_tpid,int*wstatus,intoptions);  功能:    回收指定的子进程空间  参数:    pid:要回收的子进程的pid    wstatus:回收状态的指针    options:回收选项      0阻......
  • 编程小白如何成为大神?大学新生的最佳入门攻略
    编程小白如何成为大神?大学新生的最佳入门攻略编程已成为当代大学生的必备技能,但面对众多编程语言和学习资源,新生们常常感到迷茫。如何选择适合自己的编程语言?如何制定有效的学习计划?如何避免常见的学习陷阱?让我们一起探讨大学新生入门编程的最佳路径,为你的大学生活和未来职业......