Python实现web聊天室

使用Python模块中的select模块实现web聊天室功能

select模块

Python中的select模块专注于I/O多路复用,提供了select  poll  epoll三个方法(其中后两个在Linux中可用,windows仅支持select),另外也提供了kqueue方法(freeBSD系统)

参数: 可接受四个参数(前三个必须)

    rlist: wait until ready for reading

    wlist: wait until ready for writing

    xlist: wait for an “exceptional condition”

    timeout: 超时时间

select方法:

    每次调用slect都要将所有的fd拷贝到内核空间(每次都要拷贝),导致效率下降

    每次调用slect都要将所有的fd拷贝到内核空间(每次都要拷贝),导致效率下降

    监听的的实现是通过遍历所有的fd,(遍历消耗的时间消耗多)判断是否有数据访问

    最大连接数(input中放的文件描述符数量1024)

pull方法:

    最大连接数没有限制了,除此之外和select一样。使用较少

epull方法:

    内部通过3个函数实现(select是其中一个)

    第一个函数:       创建epoll句柄,把所有的fd拷贝到内核空间,只需要拷贝一次

    第二个函数: 回调函数     某一个函数或者动作成功完成后,会自动触发一个函数为所有的fd绑定一个回调函数,一旦有数据访问,触发改回调函数,回调函数把fd放到链表中。(只要有活动,把fd放到链表中,动态监听)这样就提高了效率。例子:交试卷

    第三个函数,判断链表是否为空

server端代码

#/usr/bin/env python  #-*- coding:utf-8 -*-  import socket  import select  # 封装  class SelectServer(object):      # 定义主函数      def __init__(self, host, port, backlog):          self.host = host          self.port = port          self.address = (host, port)          self.backlog = backlog          self.server = None          self.socketList = list()        def _initSocket(self):          self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)          self.server.bind(self.address)          self.server.listen(self.backlog)          self.socketList.append(self.server)          print("chat room has start!")          while 1:              rlist, wlist, elist = select.select(self.socketList, [], [])              for r in rlist:                  if r == self.server:                      serverConn, clienAddr = self.server.accept()                      self.socketList.append(serverConn)                      print("{0}进入了房间".format(clienAddr))                      self.broadcast(r, "{0}进入了房间".format(clienAddr))                  else:                      try:                          data = r.recv(2048)                          if data:                              print("{0}: {1}".format(clienAddr, data))                              self.broadcast(r, "{0}: {1}".format(clienAddr, data))                      except Exception as e:                          self.broadcast(r, "{0}下线".format(clienAddr))                          print("{0}下线".format(clienAddr))                          r.close()                          self.socketList.remove(r)          self.server.close()      # 定义广播函数      def broadcast(self, r, data):          for i in self.socketList:              if i != r and i != self.server:                  try:                      i.sendall(data)                  except:                      i.close()                      self.socketList.remove(i)  # 定义main函数  def main():      selectServer = SelectServer(host="192.168.154.131", port=9999, backlog=5)      selectServer._initSocket()    if __name__ == '__main__':      main()

client端代码

#/usr/bin/env python  #-*- coding:utf-8 -*-  import socket, select, string, sys  import time    # main function  if __name__ == "__main__":      host = "192.168.154.131"      port = 9999      s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)      s.settimeout(2)      try:          s.connect((host, port))      except:          print('Unable to connect')          sys.exit()      print('Connected to remote host. Start sending messages')        while 1:          rlist = [sys.stdin, s]          read_list, write_list, error_list = select.select(rlist, [], [])          for sock in read_list:              if sock == s:                  data = sock.recv(2048)                  if not data:                      continue                  else:                      sys.stdout.write(data)              else:                  msg = raw_input("我说: ")                  s.sendall(msg)