本文的文字及图片来源于网络,仅供学习、交流使用,不具备任何商业用途,版权归原做者全部,若有问题请及时联系咱们以做处理。python
做者: Python应用宝典数据库
PS:若有须要Python学习资料的小伙伴能够加点击下方连接自行获取服务器
http://note.youdao.com/noteshare?id=3054cce4add8a909e784ad934f956cef微信
原理简介网络
在咱们今天的教程中,将用到即时通信的概念,即时通信容许两人或多人同时使用网络传递文字信息、文字、语音等。即时通信通常都基于socket链接,socket链接可用于发送或接受数据,通常的组合形式是IP+端口号。多线程
也就是说,在咱们的例子中,聊天的双方,由一方要承担“服务器 ” 的责任,维持一个socket服务器,等待链接进入;另外一方则是“客户端”,在服务器端维持等待状态时便可发送请求,创建链接。socket
当你和ta想进入“小黑屋 ” 里聊天的时候,只有有一方充当服务器,另外一方充当客户端便可,做为“服务器端 ” 的那我的,在微信中将IP和端口号告诉对方,便可构建链接,在小黑屋里聊天,这个小黑屋里的数据不会被任何数据库保留(除非你本身作了一个保存的数据库)。tcp
服务器端函数
聊天的时候,咱们有时候会遇到双方同时发消息的状况。这种聊天方式就叫全双工聊天方式:“服务器”可向“客户端”发送消息,“客户端”也可向“服务端”发送消息,并且容许同时发送消息。学习
服务器端怎么实现全双工的聊天方式呢?其实很简单,只要用多线程就好了,主线程用于接收客户端的链接,链接成功后新建两个线程:一个用于发送消息,一个用于接收消息:
首先,创建socket服务器:
1 import socket 2 import traceback 3 # 设定ip和端口号 4 host = '' 5 port = 51423 6 # 创建socket服务器 7 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 8 s.bind((host,port)) 9 s.listen() 10 while True: 11 # 等待链接 12 try: 13 clientsock, clientaddr = s.accept() 14 except KeyboardInterrupt: 15 raise 16 except: 17 traceback.print_exc() 18 continue
其中,AF_INET指的是用IPv4进行通讯,而SOCK_STREAM指的是TCP协议。端口号你能够随意设定,服务器端的IP地址默认为空便可。
在while循环中不断等待用户的链接。若是有用户链接成功了,咱们将进入下一步,分别创建发送和接受线程:
1 # 创建接收线程 2 t = _thread.start_new_thread(processRecv, (clientsock,)) 3 4 # 创建发送线程 5 r = _thread.start_new_thread(processSend, (clientsock,))
clientsock就是咱们获得的socket链接,processRecv和processSend分别用于处理接受信息和处理发送信息:
1 import _thread 2 def processRecv(clientsock): 3 """ 4 接受消息 5 :param clientsock: 客户端的socket链接 6 """ 7 while True: 8 data = clientsock.recv(4096) 9 if not len(data): 10 break 11 print (data.decode('utf-8')) 12 clientsock.close() 13 14 def processSend(clientsock): 15 """ 16 发送消息 17 :param clientsock: 客户端的socket链接 18 """ 19 while True: 20 data = input("> ") 21 data = data 22 clientsock.sendall(data.encode('utf-8')) 23 clientsock.close()
有个小细节要注意,socket链接的sendall函数只支持bytes类型的数据,因此咱们要encode('utf-8')。
服务端的全部代码就这样,没错,就是这么简单。
客户端则更简单,主线程自己设定为接受消息,那么咱们只须要多一个线程用于发送消息便可。客户端的所有代码以下:
1 import _thread 2 import sys 3 from socket import * 4 5 def send_message(tcpCliSock): 6 """ 7 发送信息 8 :param tcpCliSock: 与服务端的socket链接 9 """ 10 while True: 11 message = input('> ') 12 if not message: 13 break 14 tcpCliSock.send(message.encode('utf-8')) 15 16 tcpCliSock.close() 17 18 if(len(sys.argv) < 3): 19 HOST = 'localhost' 20 PORT = 51423 21 else: 22 HOST = sys.argv[1] 23 PORT = int(sys.argv[2]) 24 25 BUFSIZ = 1024 26 ADDR = (HOST,PORT) 27 28 tcpCliSock = socket(AF_INET,SOCK_STREAM) 29 tcpCliSock.connect(ADDR) 30 31 # 创建发送消息的线程 32 s = _thread.start_new_thread(send_message, (tcpCliSock,)) 33 34 while True: 35 rdata = tcpCliSock.recv(BUFSIZ) 36 if not rdata: 37 break 38 print (rdata.decode('utf-8')) 39 40 tcpCliSock.close()
其中,HOST部分填写对方的IP,PORT部分填写端口号。sys.argv用于经过参数输入这两个值,好比咱们将客户端文件命名为:client.py, 在cmd中输入:
python client.py 127.0.0.1 51423