【Python】iichats —— 命令行下的局域网聊天程序
转载请声明出处: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还请多多指教~
#!/usr/bin/python
#coding:utf8
#python 2.7.6 import threading
import socket
import time
import os
import sys
import signal
from readline import get_line_buffer
BUFSIZE = 1024
BACKPORT = 7789 #状态监听端口
CHATPORT = 7788 #聊天信息发送窗口
START = '>>'
INIT = '>>'
users = {}
ips = {}
#起到双向字典的作用,ip和name互相映射 #数据处理类(消息封装、分解)
class Data():
def gettime(self):
return time.strftime('%Y-%m-%d %H:%M', time.localtime(time.time()))
def getip(self):
ip = os.popen("/sbin/ifconfig | grep 'inet addr' | awk '{print $2}'").read()
ip = ip[ip.find(':')+1:ip.find('\n')]
return ip
def handlebc(self, data):
data = data[5:]
res = data.split('#opt:')
return res
def makebc(self, name, switch):
data = 'name:%s#opt:%d' % (name, switch)
return data
def handlechat(self, data):
msg = '\n' + self.gettime() + '\n' +'from '+ data + '\n'
return msg
def makechat(self, data, name):
return name + ':' + data #后台监听类
class Back(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.data = Data()
self.addrb = ('255.255.255.255', BACKPORT)
self.addrl = ('', BACKPORT)
self.name = socket.gethostname()
self.ip = self.data.getip()
self.thread_stop = False
def status(self, name, switch):
if switch == 0:
status = 'offline'
elif switch == 1:
status = 'online'
#用来处理输入过程中被线程返回消息打乱的情况
if outmutex.acquire(1):
sys.stdout.write('\r'+' '*(len(get_line_buffer())+len(START))+'\r')
print '[status] '+name+' '+status
sys.stdout.write(START+get_line_buffer())
sys.stdout.flush()
outmutex.release()
def broadcast(self, switch):
bsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
bsock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
data = self.data.makebc(self.name, switch)
bsock.sendto(data, self.addrb)
bsock.close()
def response(self, addr, switch):
rsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
data = self.data.makebc(self.name, switch)
rsock.sendto(data, (addr, BACKPORT))
rsock.close()
def check(self):
if usermutex.acquire():
ips.clear()
users.clear()
usermutex.release()
self.broadcast(1)
def run(self):
lsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
lsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
lsock.bind(self.addrl)
self.broadcast(1)
while not self.thread_stop:
data, addr = lsock.recvfrom(BUFSIZE)
datalist = self.data.handlebc(data)
if usermutex.acquire(1):
if datalist[1] == '':
if ips.has_key(addr[0]):
if anoun == 1:
self.status(datalist[0], 0)
del ips[addr[0]]
del users[datalist[0]]
elif datalist[1] == '':
if anoun == 1 and datalist[0] != self.name:
self.status(datalist[0], 1)
users[datalist[0]] = addr[0]
ips[addr[0]] = datalist[0]
self.response(addr[0], 2)
elif datalist[1] == '':
if anoun == 1 and datalist[0] != self.name:
self.status(datalist[0], 1)
users[datalist[0]] = addr[0]
ips[addr[0]] = datalist[0]
usermutex.release()
lsock.close()
def stop(self):
self.broadcast(0)
self.thread_stop = True #聊天类
class Listen(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.addr = ('', CHATPORT)
self.name = socket.getfqdn(socket.gethostname())
self.data = Data()
self.thread_stop = False
def ans(self, addr):#to be added 用来确认消息报的接受
return
def run(self):
lsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
lsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
lsock.bind(self.addr)
while not self.thread_stop:
data, addr = lsock.recvfrom(BUFSIZE)
msg = self.data.handlechat(data)
if outmutex.acquire(1):
sys.stdout.write('\r'+' '*(len(get_line_buffer())+len(START))+'\r')
print msg
sys.stdout.write(START+get_line_buffer())
sys.stdout.flush()
outmutex.release()
lsock.close()
def stop(self):
self.thread_stop = True #启动入口类
class Start():
def __init__(self):
self.name = socket.getfqdn(socket.gethostname())
self.data = Data()
self.listen = Listen()
self.back = Back()
print '******* iichats ********'
print ' Written by Kevince \n'
print 'This is ' + self.name
print self.data.gettime()+'\n'
#帮助信息
def helpinfo(self):
if outmutex.acquire(1):
print "use ':' to use options"
print "\t:exit\t\t\texit iichats"
print "\t:list\t\t\tlist online users"
print "\t:quit\t\t\tquit the chat mode"
print "\t:chat [hostname]\tchatting to someone"
print "\t:set status [on|off]\tturn on/of status alarms"
outmutex.release()
def refresh(self):
if outmutex.acquire(1):
print '\n******Onlinelist******'
for key in users:
print key
print '**********************\n'
outmutex.release()
def chatting(self):
csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
if outmutex.acquire(1):
print "use ':help' to get help information"
outmutex.release()
name = ''
address = ''
global anoun
global START
while True:
arg = raw_input(START)
if arg[0:5] == ':quit' and START != INIT:
name = ''
address = ''
START = INIT
elif arg[0] == ':' and START == INIT:
if arg[1:] == 'exit':
break
elif arg[1:5] == 'list':
self.refresh()
continue
elif arg[1:12] == 'set status ':
if arg[12:] == 'on':
anoun = 1
elif arg[12:] == 'off':
anoun = 0
continue
elif arg[1:5] == 'help':
self.helpinfo()
continue
elif arg[1:6] == 'check':
self.back.check()
print 'checking the list...'
time.sleep(3)
if outmutex.acquire(1):
outmutex.release()
self.refresh()
elif arg[1:6] == 'chat ':
name = arg[6:]
if usermutex.acquire(1):
userlist = users.keys()
usermutex.release()
if name not in userlist:
if outmutex.acquire(1):
print 'this host does not exist'
outmutex.release()
continue
address = (users.get(name), CHATPORT)
if outmutex.acquire(1):
print 'now chatting to ' + name+" ,use ':quit' to quit CHAT mode"
START = name + INIT
outmutex.release()
else:
if outmutex.acquire(1):
print "invalid input, use ':help' to get some info"
outmutex.release()
else:
if not len(address):
if outmutex.acquire(1):
print "you can CHAT to someone, or use ':help'"
outmutex.release()
continue
data = arg
msg = self.data.makechat(data, self.name)
csock.sendto(msg, address)
csock.close()
def start(self):
self.back.setDaemon(True)
self.back.start()
self.listen.setDaemon(True)
self.listen.start()
self.chatting()
self.back.stop()
self.listen.stop()
sys.exit() usermutex = threading.Lock()
outmutex = threading.Lock()
#控制status on和off的情况
anoun = 1
s = Start()
s.start()
【Python】iichats —— 命令行下的局域网聊天程序的更多相关文章
- Linux命令行下如何终止当前程序
Linux命令行下如何终止当前程序 快捷键: Ctrl+c 在命令行下起着终止当前执行程序的作用, Ctrl+d 相当于exit命令,退出当前shell Ctrl+s 挂起当前shell(保护作用很明 ...
- [兴趣使然]用python在命令行下画jandan像素超载鸡
下午刷煎蛋的时候看到 Dthalo 蛋友发的系列像素超载鸡,就想自己试试用python脚本画一个,老男孩视频里的作业真没兴趣,弄不好吧没意思,往好了写,自己控制不好,能力不够. 所以还是找自己有兴趣的 ...
- python命令行下tab键补全命令
在python命令行下不能使用tab键将命令进行补全,手动输入又很容易出错. 解决:tab.py #/usr/bin/env python # -*- coding:utf-8 -*- ''' 该模块 ...
- Python安装后在CMD命令行下出现“应用程序无法启动.............”问题
问题存在之一:系统是刚刚重做的精简版服务器系统(阉割版) AN就是在阿里云上刚开的Windows Server 2008 系统上碰到的 吓尿了都 症状: 正常安装python环 ...
- 命令行下查看python和numpy的版本和安装位置
命令行下查看python和numpy的版本和安装位置 1.查看python版本 方法一: python -V 注意:‘-V‘中‘V’为大写字母,只有一个‘-’ 方法二: python --versio ...
- 修复python命令行下接收不到参数的问题
由于之前安装过多个python版本,导致出现了在命令行下直接给py文件传递参数的时候接收不到,即使重新卸载安装也没有解决. 解决办法: 修改如下图路径下的键值为:"D:\Python27\p ...
- windows下安装python、环境设置、多python版本的切换、pyserial与多版本python安装、windows命令行下切换目录
1.windows下安装python 官网下载安装即可 2.安装后的环境设置 我的电脑--属性--高级--设置path的地方添加python安装目录,如C:\Python27;C:\Python33 ...
- DAY2 Python 标准库 -> Getpass 模块 -> 命令行下输入密码的方法.
getpass 模块 getpass 模块提供了平台无关的在命令行下输入密码的方法. getpass(prompt) 会显示提示字符串, 关闭键盘的屏幕反馈, 然后读取密码. 如果提示参数省略, 那么 ...
- Python Trick —— 命令行显示
1 应用场景 在命令行展示下,有以下两种场景. 进度条显示.在同一行展示不断的更新的进度条. 信息显示/隐藏控制.比如希望向多个用户展示不同信息,各个用户彼此保密. 2 进度条展示 跟c语言类似,打印 ...
随机推荐
- MYSQL 表分区的 3 方法
背景知识: 表分区是把逻辑上同一范围的数据保存到同一个文件中,就和超市一样,把同类商品放在同一个区域,把不同的商品放在不同的地方.不同的是超市中 是根据用途分类的,表分区是根据它的取值区间来分的. 分 ...
- C/S与B/S
C/S架构简要介绍 在了解什么是B/S架构之前,我们有必要了解一下什么是C/S架构: C/S架构是第一种比较早的软件架构,主要用于局域网内.也叫 客户机/服务器模式. 它可以分为客户机和服务器两层:第 ...
- delete 多表删除的使用(连表删除)
delete 多表删除的使用 1.从数据表t1中把那些id值在数据表t2里有匹配的记录全删除掉 DELETE t1 FROM t1,t2 WHERE t1.id=t2.id 或 DELETE ...
- linux的NetworkManager服务(转)
在开启NetworkManager服务的情况下,在终端下敲“service network restart”命令: 正在关闭接口 eth0: 设备状态:3 (断开连接) [确定] 正在关闭接口 eth ...
- linux之SQL语句简明教程---函数
既然数据库中有许多资料都是已数字的型态存在,一个很重要的用途就是要能够对这些数字做一些运算,例如将它们总合起来,或是找出它们的平均值.SQL 有提供一些这一类的函数.它们是: AVG (平均) COU ...
- 二探ListView
使用draw9patch 打开内置terminal 输入CD C:\Users\Gaby\AppData\Local\Android\sdk 在该目录下输入draw9patch 导入图片,开始绘制 本 ...
- hdu 5615 Jam's math problem(判断是否能合并多项式)
方法一:由十字相乘相关理论我们能知道,如果要有p,k,q,m,那么首先要有解,所以b*b-4*a*c要>0,然而因为p,k,q,m是正整数,所以代表x1,x2都是有理数,有理数是什么鬼呢?就是解 ...
- TestWriter自动化测试介绍
简介: TestWriter是上海博为峰结合多年为企业做测试服务的经验所研发的一款具有自主知识产权的自动化测试工具,为企业用户提供真正的低成本.高效率的自动化测试,引领软件测试自动化运用由技术层面向业 ...
- swift锁屏播放,音乐进度更新,专辑,歌手名显示
我自己用的音乐播放器是自带的AVPlayer 导入头文件#import <MediaPlayer/MediaPlayer.h> 远程控制事件接收与处理- (void)viewWillApp ...
- Malloc碎碎念
(以前为给同学分享写的点东西,很基础.)现在的比赛中堆溢出非常常见,对于glibc下malloc的理解也要深入一些. malloc_chunk的对齐属性 在glibc中,malloc_chunk以 2 ...