如果你仔细看我之前的博客,会看到那个手机打电话的示例,但是那段代码彻底写死了,真正编程的时候一定要写活了,不信你看看很多的程序的配置文件就是这样的,为什么单独分离个配置文件出来,就是为了便于修改配置,这就是把程序写活的最好的例子。
言归正传,直接上代码。
服务端:
from socket import *
ip_port=('127.0.0.1',8080)
backlog=5
buffer_size=1024tcp_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=1024tcp_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=1024tcp_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=1024tcp_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> 因为服务端没有收到消息,自然也没办法给客户端返回消息,所以客户端也会一直处于等待状态,从来两边都是卡死状态了。
以上就是客户端和服务端之间通信的真正原理,搞明白这个很重要,这就是我一直强调的对待知识一定要知其然且知其所以然。
继续借此平台阐发我的哲学思想,学习任何知识其实是有方法的,简而化之就是三步:
第一步:输入知识
第二步:理解消化
第三步:灵活运用
记住我的话,读书是学习,看视频课程是学习,生活处处是学习,但还有个最重要的学习叫做运用。