Created
April 25, 2017 05:52
-
-
Save suncle1993/cbbc2aa1d386106b716471e0c4661aaf to your computer and use it in GitHub Desktop.
Python TCP聊天室服务端
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import socket | |
import threading | |
class TcpChatServer: | |
def __init__(self, ip='192.168.110.13', port=9001): | |
self.ip = ip | |
self.port = port | |
self.clients = {} | |
self.sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM) | |
self.event = threading.Event() | |
def recv(self, so, ip ,port): | |
while not self.event.is_set(): | |
data = so.recv(1024).decode() # 将接受到的字节数据bytes转化为utf-8格式的字符串 | |
if data.strip() == '/quit': # 客户端主动断开时的处理 | |
so.close() | |
self.clients.pop((ip, port)) | |
return | |
for s in self.clients.values(): # 广播发送 | |
s.send('{}:{}\n{}'.format(ip, port, data).encode()) | |
def accept(self): | |
while not self.event.is_set(): | |
so, (ip, port) = self.sock.accept() | |
self.clients[(ip, port)] = so | |
# 因为so.recv会产生阻塞,因此单独开一个线程处理数据的接受部分。这样accept可以继续接受来自其他客户端的链接 | |
threading.Thread(target=self.recv, args=(so, ip, port), name='client-{}:{}'.format(ip, port)).start() | |
def start(self): | |
self.sock.bind((self.ip, self.port)) | |
self.sock.listen() | |
t = threading.Thread(target=self.accept, daemon=True) # 为了不阻塞主线程,单独开启一个线程处理accept(accept会阻塞线程) | |
try: | |
t.start() | |
t.join() # 阻塞直到获取到KeyboardInterrupt | |
except KeyboardInterrupt: | |
self.stop() | |
def stop(self): | |
for s in self.clients.values(): | |
s.close() | |
self.sock.close() | |
self.event.set() # 停止所有的循环 | |
if __name__ == '__main__': | |
tcp_chat_server = TcpChatServer() | |
tcp_chat_server.start() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment