写在前面

昨天的初识PythonSocket大概讲了下Python Socket的知识,觉得不是很深入(其实这篇也只是个皮毛对知识的一个总结), 觉得理解Socket的原理对自己还是挺有帮助的. 对于 Web 的原理对于为什么 RESTful 为什么会成为Api接口的公认形式的理解还是非常有帮助.在深入之前我们还是首先要理解一些术语.

Socket

网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket
A socket is an endpoint for communication between two machines.

是的,从名字上我们可以知道 Socket 一个管道中两端的末端。试想网络通信好比一个水管,而 Socket 就是入水口(发送方)或是出水口(接收方). 那么既然只是两个端点她就不会在乎中间经过的媒介是什么,是水管(直连),是游泳池(局域网),是城市管网(城域网),是世界地下水系统(Internet)的方式都无所谓了.

协议(protocol)

又称为通信协议

是对数据格式和计算机之间交换数据时必须遵守的规则的正式描述
a communication protocol is a system of rules that allow two or more entities of a communications system to transmit information via any kind of variation of a physical quantity.

Socket支持 TCP 以及 UDP. 这里就不扩展开来了.

Server

服务端,一个用于等待客户端请求以及服务和处理客户端请求的并响应的一端

Client

客户端, 是这个服务的另外一端. 用于发送请求.

What we are building 我们将要做什么

我们将要简单的实现一个服务端和一个客户端。 服务端开启了一个Socket端口等待客户端的链接。一旦客户端连接上了,她可以发送一些信息。同时,服务端可以处理(在这里就只是简单的转换为大写)客户端发送过来的信息再返还回客户端.这是很简单感觉但也很直白说明的一种实现方式,基本上都是 等待响应 -> 发送信息 -> 处理信息 -> 返回信息 这样即完成了一次通信.下面我们先来看看代码的实现其实就是昨天的service代码以及今天新增的client代码, 然后在讲讲她们的实现过程.

创建两个文件

  • server.py
  • client.py

server.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import socket

def Main():
host = "127.0.0.1"
port = 5000

mySocket = socket.socket()
mySocket.bind((host,port))

mySocket.listen(1)
conn, addr = mySocket.accept()
print ("Connection from: " + str(addr))
while True:
data = conn.recv(1024).decode()
if not data:
break
print ("from connected user: " + str(data))

data = str(data).upper()
print ("sending: " + str(data))
conn.send(data.encode())

conn.close()

if __name__ == '__main__':
Main()

下面我们来看看上面的服务端代码做了什么

  1. 首先我们导入了Python的Socket库
  2. 接着我们定义了 main 函数
  3. 我们定义了两个变量 host 以及 port 用于保存服务端接受数据的IP地址和端口,这里是本地网所以往往就是 127.0.0.1, 5000 端口只是我随意选择的一个如果你自己也可以随意选择一个另外的,只是这里需要注意一下必须是超过1024的端口号,因为<=1024是系统预留的,不然会引起不必要的麻烦比如23 24 53 80 8080这些等等.
  4. 之后我们定义了一个变量 mySocket, 这是Python socket的一个实例
  5. 在服务端我们必须要绑定IP地址和端口号,调用的方法是 .bind() . 这里需要注意的是 .bind() 接受的是一个Tuple. 因此我用了双括号. 其实你也可以写成 address = ("127.0.0.1", 5000) 然后直接传入 .bind 也可以。上面的写法更便于理解而已.
  6. 接下来我们调用了 .listen() 并且给了个1给她,意思就是开始持续地监听上面我们绑定的IP地址下面的5000端口直到我们关闭连接.
  7. 一切都设置好了,那么我们怎么知道 Who 发送过来的 What 呢,我们就定义了两个变量 conn连接addr地址 用来保存这两个东西.
  8. While 循环中就是server代码的核心了. 我们知道连接已经建立起来的那么久设置了一个while True的循环用于等待接收接下来 client.py发送过来的信息,但这个过程当中连接状态是没有关闭的. 我们申明了一个变量 data 用于接收客户端发送过来的数据并且解码了它, 这里非常注意在Python3中使用的是decode而不是str()来转换buffer的数据了. .rect(1024)中的1024是缓存接受到数据的一个大小.
  9. 接下来把接收到的data进行处理, 判断是否为空 转换大小写 打印接收到的数据等等 内部的一些操作. 之后把加工完的数据在.encode()之后通过.send()返回给客户端.
  10. 直到我们的客户端不再发送信息过来的时候我们就调用 .close()来关闭这个连接了。或者自己关闭服务端的运行.

client.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import socket

def Main():
host = '127.0.0.1'
port = 5000

mySocket = socket.socket()
mySocket.connect((host,port))

message = input(" -> ")

while message != 'q':
mySocket.send(message.encode())
data = mySocket.recv(1024).decode()

print ('Received from server: ' + data)

message = input(" -> ")

mySocket.close()

if __name__ == '__main__':
Main()

我们来看看客户端做了些什么, 和服务端很差不多其相似的地方就简单带过。

  1. 导入socket库,申明变量用于存放IP地址、端口、Socket实例等
  2. 不同于server端需要的是 .bind() 绑定,客户端需要的是 .connect() 连接, 这里注意地址和端口都是服务端的。很容易理解,你要写信给别人就需要填写对方的收信地址和收件人。
  3. 接下来就是等待我们出入需要发送的信息,直到输入的内容是q就关闭这个连接, 同时由于服务端收到了关闭连接的状态,也会关闭这个connection

Let’s runing it

Server

1
2
3
4
5
6
> python3 server.py
Connection from: ('127.0.0.1', 53703)
from connected user: I am Simon
sending: I AM SIMON
from connected user: This is a test
sending: THIS IS A TEST

Client

1
2
3
4
5
6
> python3 client.py
-> I am Simon
Received from server: I AM SIMON
-> This is a test
Received from server: THIS IS A TEST
-> q

EOF.