# coding=utf-8
import socket,threading,time
'''代码说明:
1.创建一个字典用于接受客户端的用户名和信息
2.创建一个类对象client用于编写客户端套接字对象发送(sendMsg)、接收数据(recv)
获取用户名(getID)、关闭服务器(close)和获取时间(getTime)方法
3.创建函数new_client用于接收客户端的用户名和数据进行打印
创建broadcast方法进行服务器数据的发送
4.创建start_server用于开启服务器,将new_client定义为线程进行数据收发
'''
# 创建客户端存储对象
clients={}
class client(object):
def __init__(self,socket,addr,username):
# 创建连接地址对象
self.addr=addr[0]
self.port=addr[1]
# 创建用户名对象
self.username=username
# 创建套接字对象
self.socket=socket
'''用于发送数据'''
def sendMsg(self,msg,username,admin):
try:
if admin:
# 以管理员身份发送数据
self.socket.send("%s %s(管理员):%s"%(self.getTime(),username,msg).encode("utf-8"))
else:
self.socket.send("%s %s:%s"%(self.getTime(),username,msg).encode("utf-8"))
return True
except:
return False
'''用于接收套接字对象的数据'''
def recv(self,mtu=1024):
try:
# 接收套接字对象的数据
data=self.socket.recv(mtu)
if data=='!q' or data is None:
return False
return data
except:
return False
'''用于关闭套接字对象'''
def close(self):
try:
# 关闭套接字对象
self.socket.close()
return True
except:
return False
'''用于获取用户名'''
def getID(self):
return "%s-%s" %(self.addr,self.port)
'''用于获取当前时间'''
def getTime(self):
# 以年月日时分秒的形式返回当前时间
return str(time.strftime("%Y-%m-%d %H:%M:%S"))
'''用于创建套接字对象并获取用户名和数据'''
def new_client(c):
try:
# 开始连接
print("%s(%s)尝试连接" %(c.addr,c.port))
data=c.recv()
# 设置用户名不为空
if data is None:
print("用户名不能为空")
return False
# 规定用户名长度
if len(data)>16:
print("用户名太长")
return False
# 将数据传回username
c.username=data
print("用户%s %s(%s)已连接" %(c.username,c.addr,c.port))
# 将连接成功的数据传回服务端
c.socket.send("已连接:".encode("utf-8"))
while True:
# 接收客户端发送的数据
data=c.recv()
if data is None:
break
else:
print("用户%s %s(%s)发送了:%s" %(c.username,c.addr,c.port,data))
broadcast(data,c.username)
# 打印关于socket的错误
except socket.error as e:
print("套接字错误:%s" % str(e))
# 打印其他错误
except Exception as e:
print("其他错误:%s" %str(e))
# 关闭服务端
finally:
print("%s(%s) 断开连接" %(c.addr,c.port))
c.close()
# 根据用户名删除客户端的信息
global client
clients.pop(c.getID())
# 用于发送客户端的所有信息
def broadcast(msg,username,admin=False):
for c in clients.values():
c.sendMsg(msg,username,admin)
'''用于创建并开启套接字对象'''
def start_server(port):
server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 设置服务端套接字对象可复用IP地址
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 设置本机IP
host="192.168.189.1"
# 给服务端绑定固定的IP地址和端口
server.bind((host,port))
# 监听客户端,最多十个客户同时连入
server.listen(10)
print(f"服务器开启,正在监听{server.getsockname()}")
while True:
# 接收客户端收到的信息
conn,addr=server.accept()
c=client(conn,addr,"")
# 将输入的用户名传给客户端套接字
clients[c.getID()]=c
t=threading.Thread(target=new_client,args=(c,)).start()
'''主函数'''
if __name__ == '__main__':
start_server(7879)
TCP服务端
# coding=utf-8
import socket
import time
from socket import *
from threading import Thread
from time import sleep
import sys
'''代码说明:再main函数中创建一个空IP地址,开始扫描服务器,当连接到服务器时自动分配同网段的IP,若同意连接则将IP传入空IP
若不连接则退出程序,创建两个线程分别用于接收服务端数据和发送数据给服务端,开启一个线程用于接收数据,当接收到数据时开启
发送数据线程,当输入!q或者不输入数据时结束程序,实现客户端的收发
'''
# 设置开启客户端的标志位
running=False
'''设置发送数据的方法'''
def send(client):
# 每次发送数据都延迟0.5s
time.sleep(0.5)
while True:
data=input("")
client.send(data.encode("utf-8"))
if data=='!q' or not data:
running=False
break
'''设置接收数据的方法'''
def recv(client,t2):
# 每次连接成功后先输入用户名
username=input("输入用户名")
# 发送用户名到服务端
client.send(username.encode("utf-8"))
# 开启发送数据的进程
t2.start()
while running:
try:
data=client.recv(1024).decode("utf-8")
if not data:
break
print(data)
except:
break
'''主函数'''
if __name__ == '__main__':
# 创建主机IP
ip=""
# 获取客户端套接字的IP地址(gethostname是获取主机名)
addrs=getaddrinfo(gethostname(),None)
# print(gethostname())
# 设置连接服务端被分配到的IP地址
print("开始扫描服务器")
# 分配主机号为100~254
for i in range(100, 254):
client=socket(AF_INET,SOCK_STREAM)
# 设置套接字对象地址可复用
client.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
# 设置套接字对象超时时间
client.settimeout(1)
temp="192.168.189.%s" %i
try:
# 连接服务端,若成功则返回0
data=client.connect_ex((temp,7788))
if data==0:
print("找到服务器")
# 设置是否连接服务器
p=input("是否连接:y/n")
# 若连接则将分配到的IP传入客户端
if p=='y':
ip=temp
break
# 若不连接则跳到程序结束关闭套接字
else:
continue
except:
print("error")
# 关闭客户端套接字
client.close()
# 若未分配到IP地址则连接失败结束程序
if ip=="":
print("未连接成功服务器")
sys.exit()
# 开启客户端套接字
client=socket(AF_INET,SOCK_STREAM)
try:
client.connect((ip,7788))
running=True
# 创建两个线程,t1用于发送数据,t1用于接收数据
t2=Thread(target=send,args=(client,))
t1=Thread(target=recv,args=(client,t2))
t1.start()
t1.join()
t2.join()
# 若有错误就调至finally
except:
pass
finally:
# 关闭客户端套接字
print("连接关闭")
client.close()
TCP客户端
刚学完套接字(socket),写了一个聊天室,用函数写了一个以后就研究了一下怎么用面向对象的方式写了一个,可能会有点问题,希望大佬指点一下