本次学习我们学习了TCP/IP的数据结构,并且根据发送的数据,对数据进行切片处理,反馈回来规定的数据。
代码:
(1)服务器端代码:
#coding:utf-8
'''
Created on 2018年9月25日
@author: zerg
'''
from socketserver import ThreadingTCPServer, StreamRequestHandler
import time
import threading
class TcpSer(ThreadingTCPServer):
def __init__(self,server_address, RequestHandler):
self.daemon_threads = True
self.allow_reuse_address = True
ThreadingTCPServer.__init__(self, server_address, RequestHandler)
class RequestHandler(StreamRequestHandler):
wfiles = []
rfiles = []
def handle(self):
flag = True
while flag:
time.sleep(0.5)
clientaddress = self.client_address
if self.wfile not in self.wfiles:
self.wfiles.append(self.wfile)
print(str(clientaddress)+"已连接")
self.wfile.write(b'hello')
self.getData()
# 服务器可以接收如下命令:help,connect,exit
# 服务器端收到help,返回“commands include help,connect,exit”
# 收到,connect,返回“connect code is 400”
# 收到,exit,返回“exit code is {500}”
# 数据解析
def getData(self):
while True:
time.sleep(0.5)
input = self.rfile.readline(1024)
input = input.decode().strip()
print(input)
if input == 'help':
self.wfile.write(b'commands include help,connect,exit')
if input == 'connect':
self.wfile.write(b'connect code is 400')
if input == 'exit':
self.wfile.write(b'exit code is {500}')
if input not in ['help','connect','exit']:
self.wfile.write(b'the command is wrong')
if __name__ == '__main__':
server_address = ('',10001)
tcp = TcpSer(server_address,RequestHandler)
print("服务已开启\r\n")
tcp.serve_forever()
(2)客户端:
#codiing:utf-8
'''
@author: 15006
'''
import socket
import threading
hostname="localhost"
port=10001
tcpclient = socket.socket()
tcpclient.connect((hostname,port))
def CmdInterface():
while True:
sendCmd = input("please input the cmd:\r\n")
tcpclient.send((sendCmd+'\r\n').encode())
cmdthread = threading.Thread(target=CmdInterface)
cmdthread.start()
def getLastData(data):
return data[len(data)-1]
def getHelpData(data):
return getLastData(data).decode().split(',')
def getConnectData(data):
return getLastData(data).decode().split(' ')
def getExitData(data):
rdata=getLastData(data).decode().split("{")
return getLastData(rdata).split("}")
while True:
recvData = tcpclient.recv(1024)
recvData = recvData.split()
data=getLastData(recvData).decode()
if (len(recvData)>3):
if (data == "{500}"):
data=getExitData(recvData)
print(data[0])
else:
data=getConnectData(recvData)
print(data)
elif (len(recvData)==3):
data=getHelpData(recvData)
print(data)
else:
print(recvData)
if __name__ == '__main__':
CmdInterface()
getLastData()
getHelpData()
getConnectData()
getExitData()
最后结果:
学习过程中的收获:
1.服务器端使用wfile进行写文件,如果客户端输入help,就反馈commands include help,connect,exit;如果客户端输入connect,就反馈connect code is 400;如果客户端输入exit,就反馈exit code is {500};如果输入其他信息,就反馈the command is wrong。
2.当接收到的数据中含有空格、回车符、换行符时,使用Strip()方法去掉。
3.使用input()方法发送数据,尤其要注意这里要添加上回车换行符\r\n
4.数据通信时候的编码和解码:在实现tcp/ip通信过程,数据的发送和接收都是通过字节的形式,结合OSI七层模型可以做到传输的时候都是二进制流的形式,而我们输入的的是字符串的格式,所以在发送字符串之前要先通过encode()编码,在接收处理前通过decode()解码。
5.由于要进行数据通信使用trading方法 进行开线程cmdthread = threading.Thread(target=CmdInterface)
cmdthread.start()
6.def getLastData(data): return data[len(data)-1] 定义一个getLastData方法返回获得数据的最后一个字节,这里的[len(data)-1]类似于数组从0开始,所以不是倒数第二个字节。
7.使用split()方法对数据进行切片,这里我们已help为例来看一下如何切片,定义的getConnectData方法通过split()方法按照" "进行分割,将'connect code is 400'分割成4个字节,然后调用getLastData方法获得数据的最后一个字节。
学习过程中遇到的问题及如何解决:
1.
这问题是因为我们输入的help、connect、exit是字符串格式,而数据的发送接收都是字节格式。
解决方法:在发送字符串之前要先通过encode()编码,在接收处理前通过decode()解码。
2.在切割'exit code is {500}'时,会留下{ }
解决方法在输出print时,使用数组的格式print(data[0]),只留下数字500
3.为什么使用send发送数据时候,服务器端无法获取?
解决方法:在结尾加上回车换行符/r/n。原因在于服务器端接收数据使用的是readline()没有接收到终止的标志,就不会停止接收数据。
还存在的问题:
1.对开线程仍然不理解,单线程和多线程有有什么样的区别。
2.网上的一些方法使用导入re库,用正则表达式配合split()来进行切割,正则表达式的使用不太懂。