1. socket 版本
此程序案列仅供参考学习,学习其中的思维
1.1 无法退出
在Linux系统中运行案列代码时存在如下问题:
- 当服务器端quit时,此时self.socket关闭,但是已经进入self.accept,而且
accept处于阻塞状态
,若不进行捕获则错误退出,若进行捕获则处于阻塞状态无法进行,因此导致start线程无法退出
- 综合考虑start线程无法退出,
主线程都已经退出,因此就不等待start线程是否完成任务,因此start线程采用deamon=True
。 - 当服务器异常终端时,客户端会处于不停的循环状态,因此需要提供
心态机制
1.2 服务器端案列程序
服务器端程序
import socket
import threading
import time
import sys
import logging
from datetime import datetime
FORMAT="%(asctime)s %(threadName)s %(thread)d %(message)s"
logging.basicConfig(format=FORMAT,level=logging.INFO)
class Chatserver:
def __init__(self):
self.sock = socket.socket()
self.event = threading.Event()
self.clients = {}
def start(self):
self.sock.bind(('0.0.0.0',8880))
self.sock.listen()
# threading.Thread(target=self.accept,name="start",deamon=True).start()
#若设置未deamon线程时,主线程quit时,start线程自然退出
threading.Thread(target=self.accept, name="start").start()
def accept(self):
print('0000good')
while not self.event.is_set():
print('111goodgoodgood')
try:
s,radd = self.sock.accept()
print('222goodgoodgood')
threading.Thread(target=self.reve,args=(s,),name="accept").start()
print('333goodgoodgood')
except OSError:
print('sssssssssssssssssssssssss')
break
def reve(self,s):
self.clients[s] = datetime.now()
print('444goodgoodgood')
while not self.event.is_set():
try:
data = s.recv(1024)
print('555goodgoodgood')
if data == b'quit':
self.clients.pop(s)
print('666goodgoodgood')
s.close()
print('7777goodgoodgood')
logging.info("{} {} -___- quit".format(s,data))
print('888goodgoodgood')
break
logging.info('{}'.format(data))
for sock in self.clients.keys():
if sock == s:
continue
sock.send(data)
print('999goodgoodgood')
except Exception:
return
def stop(self):
for so in self.clients.keys():
so.close()
self.event.set()
self.sock.close()
chat = Chatserver()
chat.start()
while True:
cmd = input(">>>")
if cmd.strip() == "quit":
chat.stop()
threading.Event().wait(3)
break
print(threading.enumerate())
1.3 客户端案列程序
import threading
import socket
import logging
import datetime
FORMAT="%(asctime)s %(threadName)s %(thread)d %(message)s"
logging.basicConfig(format=FORMAT,level=logging.INFO)
class Client:
def __init__(self, ipport=('172.16.102.100',8880)):
self.ipport = ipport
self.socket = socket.socket()
self.event = threading.Event()
def start(self):