Socket通信Python实现
最近开始看一本非常经典的网络教程,计算机网络教程:自顶向下方法,这本书的是从应用层开始写起,相对于以前坑爹的本科生教程更容易令读者感兴趣,并且循循诱导,深入浅出,是本难得的网络教程。
第二章有一个编程作业就是实现简单的Socket通信,这篇文章结合UDP和TCP的原理讲一下相关代码。值得注意的是文章中的代码使用的Python3.6的版本,所有的网络传输默认传递的是二进制比特流,因此采用了utf-8进行编码
1.Socket
Socket中文就是套接字,它是进程和网络之间的通信接口,可以简单认为它就是一个API,一个Socket由IP
+Port
构成,两个进程间如果需要通过网络通信,那么他们各自需要通过相同的Socket从网络中读/写数据,具体过程可以从下图了解。
2.UDP
首先,UDP是一个面向无连接的传输层协议,它在服务器端和客户端的功能没有太大区别,只用创建一个套接字,按照预定的业务或逻辑从套接字中进行读写。文章中UDP通信目的是利用客户端发送小写字符串,服务端将该字符串转换为大写并返回。
2.1 UDP客户端代码
按照UDP通信流程图,首先创建了套接字,设定服务端的IP地址和端口号,并组成Socket。再通过AF_INET设定网络协议为IPv4,SOCK_DGRAM设置传输层使用UDP。
from socket import *
class UdpClient:
serverName = '127.0.0.1'
serverPort = 12000
socketAddress = (serverName, serverPort)
def __init__(self):
#define the type of socket is IPv4 and Udp
self.clientSocket = socket(AF_INET, SOCK_DGRAM)
while True:
message = input("Input a lowercase sentence\n")
self.clientSocket.sendto(message.encode('utf-8'), self.socketAddress)
returnMessage, serverAddress = self.clientSocket.recvfrom(2048)
if not returnMessage:
break
print("The peersocket is: %s:%s" %(serverAddress[0], serverAddress[1]))
print("The return message is: %s" %returnMessage.decode('utf-8'))
if __name__ == '__main__':
client = UdpClient()
2.2 UDP服务端代码
服务端代码和客户端没有太多区别。
from socket import *
serverPort = 12000
serverSocket = socket(AF_INET, SOCK_DGRAM)
serverSocket.bind(('',serverPort))
print('Waiting for connection...')
while True:
message, clientAddress = serverSocket.recvfrom(2048)
print('Receive Message: %s' %message.decode('utf-8'))
modifiedMessage = message.decode('utf-8').upper()
serverSocket.sendto(modifiedMessage.encode('utf-8'), clientAddress)
3.TCP
TCP是面向连接的传输协议,需要三次握手建立连接,应用需要绑定Socket。相对于UDP多了listen
、accept
和connect
的过程。
3.1 TCP客户端
客户端代码如下,主要实现从服务端返回当前时钟的功能,与UDP的代码相差不大,因为是面向连接,所有需要多一个connect的过程:
from socket import *
serverName = '127.0.0.1'
serverPort = 11000
BUFSIZ = 1024
ADDR = (serverName,serverPort)
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect(ADDR)
while True:
data = "client message"
if not data:
break
clientSocket.send(data.encode('utf-8'))
returnData = clientSocket.recv(BUFSIZ)
if not returnData:
break
print('Return time is:%s' %returnData.decode('utf-8'))
clientSocket.close()
3.2 TCP服务端
服务端主要做了以下工作,首先绑定一个套接字,用于监听客户端的服务请求,同时这里利用listen(5)
设定最大的tcp连接数为5,然后进入循环,每次循环记录当前客户端的socket,并处理相应地业务:
from socket import *
from time import ctime
host = ''
port = 11000
ADDR = (host, port)
BUFSIZ = 1024
tcpSocket = socket(AF_INET, SOCK_STREAM)
tcpSocket.bind(ADDR)
#set the max number of tcp connection
tcpSocket.listen(5)
while True:
print('waiting for connection...')
clientSocket, clientAddr = tcpSocket.accept()
print('conneted form: %s' %clientAddr[0])
while True:
try:
data = clientSocket.recv(BUFSIZ)
except IOError as e:
print(e)
clientSocket.close()
break
if not data:
break
returnData = ctime()+data.decode('utf-8')
clientSocket.send(returnData.encode('utf-8'))
clientSocket.close()
tcpSocket.close()
这里是需要先运行server的code,再执行client的code:
➜ Py python3 TcpServer.py
➜ Py python3 TcpClient.py
Client log:
Return time is:Sun Dec 16 17:04:10 2018client message
Return time is:Sun Dec 16 17:04:10 2018client message
...
小结
Socket是网络通信中的一项重要技术,也是一种进程通信的手段,这里列出了一个简单的实现版本,有时间希望可以结合多线程完善该功能。