亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

Python網(wǎng)絡(luò)編程之使用select.select()實(shí)現(xiàn)聊天服務(wù)器

asal 2016-11-07 14:30:32 423
abstrak:第一步, 實(shí)現(xiàn)通用的send()和receive()函數(shù):send函數(shù)定義通過cPicle.dumps()將需要發(fā)送的數(shù)據(jù)序列化,然后通過socket.htonl()方法將序列化后的數(shù)據(jù)長(zhǎng)度轉(zhuǎn)化為網(wǎng)絡(luò)字節(jié)序格式,以便于底層傳輸,再將網(wǎng)絡(luò)字節(jié)序格式的長(zhǎng)度打包為'L'類型的C struct, 最后發(fā)送打包后的長(zhǎng)度以及序列化后的數(shù)據(jù)receive函數(shù)即是send反向過程,先接收到打包后的

第一步, 實(shí)現(xiàn)通用的send()和receive()函數(shù):

send函數(shù)定義通過cPicle.dumps()將需要發(fā)送的數(shù)據(jù)序列化,然后通過socket.htonl()方法將序列化后的數(shù)據(jù)長(zhǎng)度轉(zhuǎn)化為網(wǎng)絡(luò)字節(jié)序格式,以便于底層傳輸,再將網(wǎng)絡(luò)字節(jié)序格式的長(zhǎng)度打包為'L'類型的C struct, 最后發(fā)送打包后的長(zhǎng)度以及序列化后的數(shù)據(jù)

receive函數(shù)即是send反向過程,先接收到打包后的長(zhǎng)度,將其解包,然后再主機(jī)序列化,所有數(shù)據(jù)接收完成以后,返回解除序列化后的原始數(shù)據(jù)。

def send(channel, *args):
     data = cPickle.dumps(*args)
     htonl_size = socket.htonl(len(data))
     size = struct.pack("L", htonl_size)
     channel.send(size)
     channel.send(data)
 
 def receive(channel):
      recv_size = struct.calsize("L")
      data_size = channel.recv(recv_size) # receive size's value
      try:
           size = socket.ntohl(struct.unpack("L", data_size)[0])
      except struct.error, e:
           return ''
      data = ''
      while len(data) < data_size:
           data = channel.recv(data_size - len(data))
      return cPickle.loads(data)

 第二步,創(chuàng)建ChatServer類:

聊天室服務(wù)器需要能做到: 1,記錄連接數(shù)  2,記錄連接的客戶端地址以及名稱映射 ,需要時(shí)返回名稱地址 3,重用地址 4,檢測(cè)鍵盤中斷 5,處理輸入及請(qǐng)求

先實(shí)現(xiàn)1,2,3,4點(diǎn):

 class ChatServer(object):
     def __init__(self, port, backlog=5):
         self.clients = " # record client number
         self.clientmap = {} # client address and name's mapping
         self.outputs = [] # socket output objects' list
         self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
         self.server.bind((SERVER_HOST, port)
         self.server.listen(backlog)
         signal.signal(signal.SIGINT, self.sighandler)
 
     def sighandler(self, signum, frame):
         print "Shutting down server..."
         for output in outputs:
              output.close(0)
         self.server.close()
 
     def get_client_name(self, client):
         info = self.clientmap[client]
         host, name = info[0][0], info[1]
         return '@'.join((name, host))

 第5點(diǎn)處理輸入及請(qǐng)求分幾種情況,1處理客戶端接入并通知其他客戶端,2處理客戶端輸入信息并轉(zhuǎn)發(fā)給其他客戶端,處理標(biāo)準(zhǔn)輸入, 這里丟棄,3處理異常

def run(self):
         inputs = [self.server, sys.stdin] #inputs for select.select() first arg
         self.outputs = [] # define outputs for select.select(), second arg
         running = True
         while running:
             try:
                 readable, writeable, exceptional = \
                     select.selcet(inputs, self.outputs, [])
             except select.error, e:
                 break
             
             for sock in readable:
                 if sock == self.server:
                     client, address = self.server.accept()
                     print "Chat server: got connection %d from %s" % \ 
                         (client.fileno, address)
                     cname = receive(client).spilt('NAME: ')[1]
                     self.clients += 1
                     send(client, "CLIENT: " + str(address[0])
                     inputs.append(client)
                     self.clientmap[client] = (address, cname)
                     # send joining information to other clients
                     msg = '\n (Connected: New client (%d) from %s" % \
                          (self.clients, self.get_client_name(client))'
                     for output in self.outputs:
                         send(output, msg)
                     self.outputs.append(client)
               
                  elif sock == sys.stdin:
                      junk = sys.stdin.readable()
                      running = False
                  else:
                      try:
                          data = receive(sock)
                          if data:
                              msg = '\n#[' + self.get_client_name(sock) + \
                                  ']>>' + data
                              for output in self.outputs:
                                  if output != sock:
                                      send(output.msg)
                          else:
                              print "Chat server: %d hung up" % sock.fileno()
                              self.clients -= 1
                              sock.close()
                              inputs.remove(sock)
                              self.outputs.remove(sock)
                              msg = '\n(now hung up: client from %s)' % \ 
                                   sef.get_client_name(sock)
                              for output in self.outputs:
                                  send(output, msg)
                     except socket.error, e:
                         inputs.remove(sock)
                         self.outputs.remove(sock)
              
             self.server.close()

 第三步, 實(shí)現(xiàn)客戶端類。主要處理輸入與從server端返回消息的讀取

 class ChatClient(object):
     def __init__(self, name, port, host=SERVER_HOST):
          self.name = name
          self.connected = False
          self.host = host
          self.port = port
          self.prompt = "[" + \
               '@'.join((name, socket.gethostname().spilt('.')[0])) + ']>'
          try:
               self.sock = socket.socket(socket.AF_INET,  \    socket.SOCK_STREAM)
               self.sock.connect((host, port))
               print "Now connceted to chat server at port %d" % port
               self.connected = True
               send(self.sock, 'NAME: ' + self.name)
               data = receive(self.sock)
               addr = data.split('CLIENT: ')[1]
               self.prompt = '[' + '@'.join((self.name, addr)) + ']>'
         except socket.error, e:
               print "Failed to connect to chat server @ port %d" % self.port
               sys.exit(1)

客戶端類的run方法主要處理標(biāo)準(zhǔn)輸入,server返回信息,以及異常:

 def run(self):
            """client main loop"""
            while self.connected:
                try:
                    sys.stdout.write(self.prompt)
                    sys.stdout.flush()
                    #wait for input from stdin or socket
                    readable, writeable, exceptional = select.select([0, self.sock], [], [])
                    for sock in readable:
                        if sock == 0:
                            data = sys.stdin.readline().strip()
                            if data: send(self.sock, data)
                        else sock == self.sock:
                            data = receive(self.sock)
                            if not data:
                                print "Client shutting down"
                                self.connected = False
                                break
                            else:
                                sys.stdout.write(data + '\n')
                                sys.stdout.flush()
                 except KeyboardInterrupt, e:
                     print "  Client interrupted, "
                     self.sock.close()
                     break


Nota Keluaran

Penyertaan Popular