【Python】iichats —— 命令行下的局域网聊天程序

时间:2022-05-28 17:40:57

转载请声明出处:http://www.cnblogs.com/kevince/p/3941728.html   ——By Kevince

ii系列工具第三弹,命令行下的局域网聊天程序

原理:

程序启动时向全网(255.255.255.255)BACKPORT端口广播自己的主机名以及状态(上线)。

如果接受收到的上线状态,则将其加入通信列表,同时返还一个数据包,使自己也将对面加入其通信列表。

程序退出时向全网广播自己的下线状态,如果收到该下线状态则将其从自己的通信列表中删除

为了防止在输入过程中被新输出的消息打断,可以用readlines中的get_line_buffer函数获取缓冲区内的字符并储存,清空原先行,输出新结果,并在下面输出刚刚输入的内容(可用curses改进,to be continued...)

缺陷:

使用UDP协议,未添加消息到达确认机制;

跨平台支持需要修改代码(readlines只支持linux, windows下要用pyreadline,MAC OS要用edlitline来代替)

实用性不强,功能单一,学习程序

未能实现GUI图形界面的开发(目前还木有学会……)

刚学Python没多久 且开发仓促,有Bug还请多多指教~

 

  1 #!/usr/bin/python
  2 #coding:utf8
  3 #python 2.7.6
  4 
  5 import threading
  6 import socket
  7 import time
  8 import os
  9 import sys
 10 import signal
 11 from readline import get_line_buffer
 12 BUFSIZE = 1024
 13 BACKPORT = 7789     #状态监听端口
 14 CHATPORT = 7788     #聊天信息发送窗口
 15 START = '>>'
 16 INIT = '>>'
 17 users = {}
 18 ips = {} 
 19 #起到双向字典的作用,ip和name互相映射
 20 
 21 #数据处理类(消息封装、分解)
 22 class Data(): 
 23     def gettime(self):
 24         return time.strftime('%Y-%m-%d %H:%M', time.localtime(time.time()))
 25     def getip(self):
 26         ip = os.popen("/sbin/ifconfig | grep 'inet addr' | awk '{print $2}'").read()
 27         ip = ip[ip.find(':')+1:ip.find('\n')]
 28         return ip
 29     def handlebc(self, data):
 30         data = data[5:]
 31         res = data.split('#opt:')
 32         return res
 33     def makebc(self, name, switch):
 34         data = 'name:%s#opt:%d' % (name, switch)
 35         return data
 36     def handlechat(self, data):
 37         msg = '\n' + self.gettime() + '\n' +'from '+ data + '\n'
 38         return msg
 39     def makechat(self, data, name):
 40         return name + ':' + data
 41 
 42 #后台监听类
 43 class Back(threading.Thread): 
 44     def __init__(self):
 45         threading.Thread.__init__(self)
 46         self.data = Data()
 47         self.addrb = ('255.255.255.255', BACKPORT)
 48         self.addrl = ('', BACKPORT)
 49         self.name = socket.gethostname()
 50         self.ip = self.data.getip()
 51         self.thread_stop = False
 52     def status(self, name, switch):
 53         if switch == 0:
 54             status = 'offline'
 55         elif switch == 1:
 56             status = 'online'
 57         #用来处理输入过程中被线程返回消息打乱的情况
 58         if outmutex.acquire(1):
 59             sys.stdout.write('\r'+' '*(len(get_line_buffer())+len(START))+'\r')
 60             print '[status] '+name+' '+status
 61             sys.stdout.write(START+get_line_buffer())
 62             sys.stdout.flush()
 63             outmutex.release()
 64     def broadcast(self, switch):
 65         bsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 66         bsock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
 67         data = self.data.makebc(self.name, switch)
 68         bsock.sendto(data, self.addrb)
 69         bsock.close()
 70     def response(self, addr, switch):
 71         rsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 72         data = self.data.makebc(self.name, switch)
 73         rsock.sendto(data, (addr, BACKPORT))
 74         rsock.close()
 75     def check(self):
 76         if usermutex.acquire():
 77             ips.clear()
 78             users.clear()
 79             usermutex.release()
 80         self.broadcast(1)
 81     def    run(self):
 82         lsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 83         lsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
 84         lsock.bind(self.addrl)
 85         self.broadcast(1)
 86         while not self.thread_stop:
 87             data, addr = lsock.recvfrom(BUFSIZE)
 88             datalist = self.data.handlebc(data)
 89             if usermutex.acquire(1):
 90                 if datalist[1] == '0':
 91                     if ips.has_key(addr[0]):
 92                         if anoun == 1:
 93                             self.status(datalist[0], 0)
 94                         del ips[addr[0]]
 95                         del users[datalist[0]]
 96                 elif datalist[1] == '1':
 97                     if anoun == 1 and datalist[0] != self.name:
 98                         self.status(datalist[0], 1)
 99                     users[datalist[0]] = addr[0]
100                     ips[addr[0]] = datalist[0]
101                     self.response(addr[0], 2)
102                 elif datalist[1] == '2':
103                     if anoun == 1 and datalist[0] != self.name:
104                         self.status(datalist[0], 1)
105                     users[datalist[0]] = addr[0]
106                     ips[addr[0]] = datalist[0]
107                 usermutex.release()
108         lsock.close()
109     def stop(self):
110         self.broadcast(0)
111         self.thread_stop = True
112 
113 #聊天类
114 class Listen(threading.Thread):
115     def __init__(self):
116         threading.Thread.__init__(self)
117         self.addr = ('', CHATPORT)
118         self.name = socket.getfqdn(socket.gethostname())
119         self.data = Data()
120         self.thread_stop = False
121     def ans(self, addr):#to be added 用来确认消息报的接受
122         return
123     def run(self):
124         lsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
125         lsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
126         lsock.bind(self.addr)
127         while not self.thread_stop:
128             data, addr = lsock.recvfrom(BUFSIZE)
129             msg = self.data.handlechat(data)
130             if outmutex.acquire(1):
131                 sys.stdout.write('\r'+' '*(len(get_line_buffer())+len(START))+'\r')
132                 print msg
133                 sys.stdout.write(START+get_line_buffer())
134                 sys.stdout.flush()
135                 outmutex.release()
136         lsock.close()
137     def stop(self):
138         self.thread_stop = True
139 
140 #启动入口类
141 class Start(): 
142     def __init__(self):
143         self.name = socket.getfqdn(socket.gethostname())
144         self.data = Data()
145         self.listen = Listen()
146         self.back = Back()
147         print '*******   iichats   ********'
148         print '     Written by Kevince     \n'
149         print 'This is ' + self.name
150         print self.data.gettime()+'\n'
151     #帮助信息
152     def helpinfo(self):     
153         if outmutex.acquire(1):
154             print "use ':' to use options"
155             print "\t:exit\t\t\texit iichats"
156             print "\t:list\t\t\tlist online users"
157             print "\t:quit\t\t\tquit the chat mode"
158             print "\t:chat [hostname]\tchatting to someone"
159             print "\t:set status [on|off]\tturn on/of status alarms"
160             outmutex.release()
161     def refresh(self):
162         if outmutex.acquire(1):
163             print '\n******Onlinelist******'
164             for key in users:
165                 print key
166             print '**********************\n'
167             outmutex.release()
168     def chatting(self):
169         csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
170         if outmutex.acquire(1):
171             print "use ':help' to get help information"
172             outmutex.release()
173         name = ''
174         address = ''
175         global anoun
176         global START
177         while True:
178             arg = raw_input(START)
179             if arg[0:5] == ':quit' and START != INIT:
180                 name = ''
181                 address = ''
182                 START = INIT
183             elif arg[0] == ':' and START == INIT:
184                 if arg[1:] == 'exit':
185                     break
186                 elif arg[1:5] == 'list':
187                     self.refresh()
188                     continue
189                 elif arg[1:12] == 'set status ':
190                     if arg[12:] == 'on':
191                         anoun = 1
192                     elif arg[12:] == 'off':
193                         anoun = 0
194                     continue
195                 elif arg[1:5] == 'help':
196                     self.helpinfo()
197                     continue
198                 elif arg[1:6] == 'check':
199                     self.back.check()
200                     print 'checking the list...'
201                     time.sleep(3)
202                     if outmutex.acquire(1):
203                         outmutex.release()
204                     self.refresh()
205                 elif arg[1:6] == 'chat ':
206                     name = arg[6:]
207                     if usermutex.acquire(1):
208                         userlist = users.keys()
209                         usermutex.release()
210                     if name not in userlist:
211                         if outmutex.acquire(1):
212                             print 'this host does not exist'
213                             outmutex.release()
214                         continue
215                     address = (users.get(name), CHATPORT)
216                     if outmutex.acquire(1):
217                         print 'now chatting to ' + name+" ,use ':quit' to quit CHAT mode"
218                         START = name + INIT
219                         outmutex.release()
220                 else:
221                     if outmutex.acquire(1):
222                         print "invalid input, use ':help' to get some info"
223                         outmutex.release()
224             else:
225                 if not len(address):
226                     if outmutex.acquire(1):
227                         print "you can CHAT to someone, or use ':help'"
228                         outmutex.release()
229                     continue
230                 data = arg
231                 msg = self.data.makechat(data, self.name)
232                 csock.sendto(msg, address)
233         csock.close()
234     def start(self):
235         self.back.setDaemon(True)
236         self.back.start()
237         self.listen.setDaemon(True)
238         self.listen.start()
239         self.chatting()
240         self.back.stop()
241         self.listen.stop()
242         sys.exit()
243 
244 usermutex = threading.Lock()
245 outmutex = threading.Lock()
246 #控制status on和off的情况
247 anoun = 1
248 s = Start()
249 s.start()