標籤:nts rgs try 資訊 socket nal 通過 pack cts
第一步, 實現通用的send()和receive()函數:
send函數定義通過cPicle.dumps()將需要發送的資料序列化,然後通過socket.htonl()方法將序列化後的資料長度轉化為網路位元組序格式,以便於底層傳輸,再將網路位元組序格式的長度打包為‘L‘類型的C struct, 最後發送打包後的長度以及序列化後的資料
receive函數即是send反向過程,先接收到打包後的長度,將其解包,然後再主機序列化,所有資料接收完成以後,返回解除序列化後的未經處理資料。
1 def send(channel, *args): 2 data = cPickle.dumps(*args) 3 htonl_size = socket.htonl(len(data)) 4 size = struct.pack("L", htonl_size) 5 channel.send(size) 6 channel.send(data) 7 8 def receive(channel): 9 recv_size = struct.calsize("L")10 data_size = channel.recv(recv_size) # receive size‘s value11 try:12 size = socket.ntohl(struct.unpack("L", data_size)[0])13 except struct.error, e:14 return ‘‘15 data = ‘‘16 while len(data) < data_size:17 data = channel.recv(data_size - len(data))18 return cPickle.loads(data)
第二步,建立ChatServer類:
聊天室伺服器需要能做到: 1,記錄串連數 2,記錄串連的用戶端地址以及名稱映射 ,需要時返回名稱地址 3,重用地址 4,檢測鍵盤中斷 5,處理輸入及請求
先實現1,2,3,4點:
1 class ChatServer(object): 2 def __init__(self, port, backlog=5): 3 self.clients = " # record client number 4 self.clientmap = {} # client address and name‘s mapping 5 self.outputs = [] # socket output objects‘ list 6 self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 7 self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 8 self.server.bind((SERVER_HOST, port) 9 self.server.listen(backlog)10 signal.signal(signal.SIGINT, self.sighandler)11 12 def sighandler(self, signum, frame):13 print "Shutting down server..."14 for output in outputs:15 output.close(0)16 self.server.close()17 18 def get_client_name(self, client):19 info = self.clientmap[client]20 host, name = info[0][0], info[1]21 return ‘@‘.join((name, host))22
第5點處理輸入及請求分幾種情況,1處理用戶端接入並通知其他用戶端,2處理用戶端輸入資訊並轉寄給其他用戶端,處理標準輸入, 這裡丟棄,3處理異常
1 def run(self): 2 inputs = [self.server, sys.stdin] #inputs for select.select() first arg 3 self.outputs = [] # define outputs for select.select(), second arg 4 running = True 5 while running: 6 try: 7 readable, writeable, exceptional = 8 select.selcet(inputs, self.outputs, []) 9 except select.error, e:10 break11 12 for sock in readable:13 if sock == self.server:14 client, address = self.server.accept()15 print "Chat server: got connection %d from %s" % \ 16 (client.fileno, address)17 cname = receive(client).spilt(‘NAME: ‘)[1]18 self.clients += 119 send(client, "CLIENT: " + str(address[0])20 inputs.append(client)21 self.clientmap[client] = (address, cname)22 # send joining information to other clients23 msg = ‘\n (Connected: New client (%d) from %s" % 24 (self.clients, self.get_client_name(client))‘25 for output in self.outputs:26 send(output, msg)27 self.outputs.append(client)28 29 elif sock == sys.stdin:30 junk = sys.stdin.readable()31 running = False32 else:33 try:34 data = receive(sock)35 if data:36 msg = ‘\n#[‘ + self.get_client_name(sock) + 37 ‘]>>‘ + data38 for output in self.outputs:39 if output != sock:40 send(output.msg)41 else:42 print "Chat server: %d hung up" % sock.fileno()43 self.clients -= 144 sock.close()45 inputs.remove(sock)46 self.outputs.remove(sock)47 msg = ‘\n(now hung up: client from %s)‘ % \ 48 sef.get_client_name(sock)49 for output in self.outputs:50 send(output, msg)51 except socket.error, e:52 inputs.remove(sock)53 self.outputs.remove(sock)54 55 self.server.close()
Python網路編程 (三)使用select.select()實現聊天伺服器