您的位置:首页 > 编程语言 > Python开发

Socket---基于IO复用实现异步非阻塞通信 Python群聊工具

2015-12-28 19:48 721 查看
运行环境:

1. 需要安装最新的python3

sudo apt-get install python3

2.

不要用ssh shell工具连接linux机器,因为它唯一缺点就是不支持中文

可以选择使用putty连接linux,编码设置使用utf8编码,这样就可以输入中文了

运行方法:

1. 将附件脚本拷贝到linux中

2. 在linux命令行下输入:python3 client.py

3. 看到Connection established, you can input to talk now, enjoy your time! 后可以输入说话的内容了

待改进地方:

1. UI取代命令行

2. 更多的异常处理

服务器端程序:

import socket
import signal
import select
MAX_LISTEN_N = 100
MAX_BUFFER_N = 1024
mconnections = {}
addresses = {}
datalist = {}
IP_ADDR = '192.168.1.2'
PORT = 4547

def remove_fd_data(fd):
mconnections.pop(fd)
addresses.pop(fd)
datalist.pop(fd)

def signal_handler(signum, frame):
print("signum=",signum)

def prepare_socket():
#print('prepare_socket')
listen_fd = socket.socket(socket.AF_INET, socket.SOCK_STREAM,0)
listen_fd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,True)
listen_fd.bind((IP_ADDR,PORT))
listen_fd.listen(MAX_LISTEN_N)
signal.signal(signal.SIGILL,signal_handler)
signal.signal(signal.SIGPIPE,signal_handler)
return listen_fd

def handle_accept(listen_fd,epoll_fd):
client_socket,(client_addr,client_port) = listen_fd.accept()
print('accept a new client:',client_socket.fileno())
epoll_fd.register(client_socket.fileno(),select.EPOLLIN)
mconnections[client_socket.fileno()]=client_socket
addresses[client_socket.fileno()]=client_addr
datalist[client_socket.fileno()]=''

def handle_read(fd,epoll_fd):
print('handle_read:',fd)
data_s=''
while True:
data=mconnections[fd].recv(MAX_BUFFER_N)
#print(data)
if not data and not data_s:
epoll_fd.unregister(fd)
mconnections[fd].close()
remove_fd_data(fd)
print("Client is closed abnormally:",fd)
return
elif len(data)==MAX_BUFFER_N:
data_s+=data.decode('utf-8')
continue
else:
data_s+=data.decode('utf-8')
break
#print("receive new data:",data_s)
datalist[fd]=data_s
epoll_fd.modify(fd,select.EPOLLOUT)

def handle_write_single(epoll_fd, fd, talk):
print("handle_write_single:", fd)
slen = 0
while True:
slen+=mconnections[fd].send(talk[slen:])
if slen == len(talk):
#print('send finished')
break
else:
print('send continue')
break
epoll_fd.modify(fd,select.EPOLLIN)

def get_host_name(fd):
name,alias,ips = socket.gethostbyaddr(addresses[fd])
if len(ips)>0:
return ips[0]
else:
return 'Unknown name'

def handle_write(fd,epoll_fd):
#print('handle_write')
mset = mconnections.keys()
#length = len(mset)
#print("length:",length)
ip_name = get_host_name(fd)+':  '

#handle normal exit case
if True == (datalist[fd] == 'exit'):
print("Client want to exit now:",fd)
handle_write_single(epoll_fd,fd,datalist[fd].encode('utf-8'))
epoll_fd.unregister(fd)
mconnections[fd].close()
remove_fd_data(fd)
return

for item in mset:
print(fd,":",item)
if fd == item:
print('ignore itself')
else:
handle_write_single(epoll_fd,item,(ip_name+datalist[fd]).encode('utf-8'))
epoll_fd.modify(fd,select.EPOLLIN)

def handle_events(poll_list, listen_fd,epoll_fd):
#print('handle_events')
for fd, events in poll_list:
if fd == listen_fd.fileno() and events==select.EPOLLIN:
handle_accept(listen_fd, epoll_fd)
elif events==select.EPOLLIN:
handle_read(fd,epoll_fd)
elif events==select.EPOLLOUT:
handle_write(fd,epoll_fd)
elif events==select.EPOLLHUP:
print("Client is closed:",fd)
epoll_fd.unregister(fd)
mconnections[fd].close()
remove_fd_data(fd)
else:
continue

def prepare_epoll(listen_fd):
#print('prepare_epoll')
epoll_fd = select.epoll()
epoll_fd.register(listen_fd.fileno(),select.EPOLLIN)
while True:
poll_list = epoll_fd.poll(-1,-1)
handle_events(poll_list, listen_fd,epoll_fd)
epoll_fd.close()

if __name__ == '__main__':
listen_fd=prepare_socket()
prepare_epoll(listen_fd)
listen_fd.close()


客户端程序:

import socket
import signal
import select
import threading
MAX_BUFFER_N = 1024
IP_ADDR = '192.168.1.2'
PORT = 4547
epoll_obj = {}

def exit_client(socket_obj):
epoll_obj[0].unregister(0)

def init_socket():
return socket.socket(socket.AF_INET, socket.SOCK_STREAM,0)

def prepare_socket(socket_obj):
socket_obj.connect((IP_ADDR,PORT))
w_msg = '''Connection established, you \
can input to talk now, enjoy your time!'''
print(w_msg)

def handle_read(socket_obj,fd):
#print('handle_read')
data_s=''
is_exit = False
while True:
data=socket_obj.recv(MAX_BUFFER_N)
#print(data)
if not data and not data_s:
epoll_obj[1].unregister(fd)
print('error when read')
is_exit = True
return is_exit
elif len(data)==100:
data_s+=data.decode('utf-8')
continue
else:
data_s+=data.decode('utf-8')
break

if True == ('exit' == data_s):
epoll_obj[1].unregister(fd)
is_exit = True
print('I will exit now, see you later')
return is_exit
print('          ',data_s)
return is_exit

def handle_write_for_0(socket_obj,fd):
#print('handle_write_for_0')
is_exit = False
data = input()
socket_obj.send(data.encode('utf-8'))
if True == ('exit' == data):
is_exit = True
epoll_obj[0].unregister(0)
return is_exit

def handle_events(socket_obj,poll_list):
#print('handle_events')
is_exit = False
for fd, events in poll_list:
#print("fd:",fd)
if fd == 0:
if events==select.EPOLLIN:
continue
elif events==select.EPOLLOUT:
is_exit = handle_write_for_0(socket_obj,fd)
elif events==select.EPOLLHUP:
print("close:",fd)
epoll_obj[0].unregister(fd)
is_exit = True
else:
continue
else:
if events==select.EPOLLIN:
is_exit = handle_read(socket_obj,fd)
elif events==select.EPOLLOUT:
continue
elif events==select.EPOLLHUP:
print("close:",fd)
epoll_obj[1].unregister(fd)
is_exit = True
else:
continue
return is_exit

def start_p(socket_obj):
#print("start_p")
epoll_obj[0] = select.epoll()
epoll_obj[0].register(0,select.EPOLLOUT)
while True:
poll_list = epoll_obj[0].poll(-1,-1)
is_exit = handle_events(socket_obj,poll_list)
if is_exit==True:
break
epoll_obj[0].close()
#print("leave start_p")

def process_input(socket_obj):
#print("process_input")
t1 = threading.Thread(group=None,target=start_p, args=(socket_obj,))
t1.start()
#print("leave process_input")

def prepare_epoll(socket_obj):
#print('prepare_epoll')
epoll_obj[1] = select.epoll()
epoll_obj[1].register(socket_obj.fileno(),select.EPOLLIN)
while True:
poll_list = epoll_obj[1].poll(-1,-1)
is_exit = handle_events(socket_obj,poll_list)
if is_exit==True:
break
epoll_obj[1].close()
#print("leave prepare_epoll")

if __name__ == '__main__':
socket_obj=init_socket()
prepare_socket(socket_obj)
process_input(socket_obj)
prepare_epoll(socket_obj)
socket_obj.close()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: