Skip to content

Instantly share code, notes, and snippets.

@suncle1993
Created April 25, 2017 05:52
Show Gist options
  • Save suncle1993/cbbc2aa1d386106b716471e0c4661aaf to your computer and use it in GitHub Desktop.
Save suncle1993/cbbc2aa1d386106b716471e0c4661aaf to your computer and use it in GitHub Desktop.
Python TCP聊天室服务端
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