这个脚本创建一个Tcp服务器,他接收来自客户端的消息,然后将消息加上时间戳前缀并发送回客户端
from socket import * from time import ctime HOST = 'localhost' PORT = 9999 BUFSIZ = 1024 ADDR = (HOST, PORT) tcpSerSock = socket(AF_INET, SOCK_STREAM) tcpSerSock.bind(ADDR) tcpSerSock.listen(5) while True: print('waiting for connection..') tcpCliSock ,addr = tcpSerSock.accept() print('...connected from', addr) while True: data = tcpCliSock.recv(BUFSIZ) if not data: break tcpCliSock.send('[%s] %s' %(bytes(ctime(), 'utf-8'), data)) tcpCliSock.close() tcpSerSock.close()socketserver是标准库的一个高级模块,它的目标是简化很多样板代码,隐藏的实现细节之外,另一个不同之处就是,我们现在使用累来编写应用程序。因为以面向对象的方式处理事务有助于组织数据,以及逻辑性的将功能放在正确的地方,你还会注意到,应用程序现在是事件驱动的,这以为着只有在系统中的事件发生时,它们才会工作。
我们得到了请求处理程序MyRequestHandler,作为socketserver中StreamRequestHandler的一个子类,重写了handle()方法,该方法在基类Request中默认情况下没有任何行为
def handle(self): pass当接收到一个来自客户端的消息时,他就会调用handle()方法。
在socket中用recv()和send()来表示接收/发送 而在socketserver中self.request.recv()和self.request.send()来表示接收/发送
最后利用给定的主机欣喜和请求处理创建了TCP服务器。然后,无限循环的等待并服务于客户端请求
socketserver请求处理程序的默认行为是接收连接、获取请求,然后关闭连接。由于这个原因,我们不能在应用程序整个执行过程中都保持连接,因此每次向服务器发送信息时,都需要创建一个新的套接字
运行时可以发现,我们还是只能连接一个客户端,当第一个连接没有关闭时,第二个连接一直在等待,如何实现同时连接呢?
很简单,我们将服务端稍作修改;
# from socketserver import (TCPServer as TCT, # StreamRequestHandler as SRH) import socketserver #这里只导入socketser并不进行导入具体方法 from time import ctime HOST = '' PORT = 9999 ADDR = (HOST, PORT) BUFSIZ = 1024 class MyRequestHandler(socketserver.StreamRequestHandler):#这里和以前一样 只是换了一个写法 def handle(self): print('..connected from:', self.client_address) self.request.send(('[%s] %s' %(ctime(), self.request.recv(BUFSIZ).decode())).encode('utf-8')) if __name__ == '__main__': tcpServ = socketserver.ThreadingTCPServer(ADDR, MyRequestHandler)# tcpServ 并不是socketserver.TCPServer 而是socketserver.ThreadingTCPServer 就是字面意思 ThreadingTCPServer 使用的多线程 print('waiting for connection..') tcpServ.serve_forever()练习:(以下答案个人理解不保证正确)
1.套接字。面向连接的套接字和无连接套接字之间的区别是什么?
面向连接 是指进行通讯之前必须建立一个连接,又称为虚拟电路或流套接字。 通讯提供序列化的、可靠的和不重复的数据交付。二没有记录边界 主要协议是传输控制协议(TCP) 无连接 是指通讯之前不需要建立连接。数据报类型套接字 传输过程中无法保证他的顺序性、可靠性或重复性。然而数据报确实保存了记录边界 主要协议是用户数据报协议(UDP)2.客户端/服务器架构.用自己的话描述这个术语的意思,并给出几个例子
人们通过客户端从服务器端获取想要的内容 消费者和24小时商店的关系,消费者可以随时去进行消费,商店就相当于服务器,一直在等待着人们去消费。3.套接字。TCP和UDP之中,哪种类型的服务器接受连接,并将他们转换到独立的套接字进行客户端通信?
UDP4.客户端。更新TCP(tsTclnt.py)以使得服务器名称无需硬编码到应用程序中。此外,应该允许用户指定主机名和端口号,且如果二者中任何一个或者全部参数丢失,那么应该使用默认值
from socket import * def sock(HOST, PORT): BUFSIZ = 1024 ADDR = (HOST, PORT) print(ADDR) tcpCliSock = socket(AF_INET, SOCK_STREAM) tcpCliSock.connect(ADDR) while True: data = input('<<:') if not data: print('输入为空!') continue tcpCliSock.send(data.encode('utf-8')) data = tcpCliSock.recv(BUFSIZ) if not data: print('服务器端异常') break print(data.decode()) tcpCliSock.close() if __name__ == '__main__': HOST = input('主机名<<:') PORT = input('端口号<<:') if not HOST : HOST = 'localhost' if not PORT: PORT = 9999 sock(HOST,PORT)5.半双工聊天。创建一个简单的半双工聊天程序。指定半双工,我们呢的意思就是,当建立一个连接且服务开始后,只有一个人能打字,而另一个参与者在得到输入消息提示之前必须等待消息。并且,一旦发送者发送了一条消息,在他能够再次发送消息之前,必须等待对方回复,其中,一个参与者将在服务器一侧,而另一位在客户端一侧。
'''服务器端''' import socket HOST = '' PORT = 9999 BUFSIZ = 1024 ADDR = (HOST, PORT) server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) server.bind(ADDR) server.listen() while True: tcpClientSock, addr = server.accept() print('...connected from:', addr) while True: data = tcpClientSock.recv(BUFSIZ) if not data: print('not data') break print('recv:', data.decode()) sends = input('<<:') if not sends: continue tcpClientSock.send(sends.encode('utf-8')) tcpClientSock.close() server.close() '''客户端''' import socket HOST = 'localhost' PORT = 9999 BUFSIZ = 1024 ADDR = (HOST, PORT) client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) client.connect(ADDR) while True: data = input('<<:') if not data: continue client.send(data.encode('utf-8')) serverdata = client.recv(BUFSIZ) if not serverdata: print('服务器端无返回') break print(serverdata.decode()) client.close()