【计算机网路】一个简单的chat程序,并能互传文件(Python)

前言

这个实验已经做了一个多月了,本来打算把程序功能完善一下再分享出来,无奈最近太忙了,又怕改来改去又改崩了就迟迟未改。最近终于把想学了好久的Git学了,就把这个代码传到了Github上。后续如果不出意外的话会继续完善,借此学习版本控制。
备注:我的Github上有HNU计网Lab2完整代码,欢迎参考 链接

解决问题
  • 用户名重复提示重新输入
  • 选择服务类型
  • 用X.txt代替接收窗口,使得收发分离
  • 使用服务器作为中转站实现消息、文件转发(C/S模式)
Server
from concurrent.futures import ThreadPoolExecutor
from socket import *
import time# 发送文件def file_send(filename, clientSocket):# 异常处理 文件不存在则返回错误信息try:file = open(filename, encoding='utf-8')except FileNotFoundError:print("没找到文件,请检查你的输入")sentences = []content = file.read()# clientSocket.send(("即将传输文件:"+filename).encode('utf-8'))time.sleep(0.1)# 将content切割成长度为1024的一段段文字 最后一段<=1024while len(content) > 0:sentences.append(content[:min(len(content), 1024)])content = content[min(len(content), 1024):]  # 割了就扔掉# 循环发送切割后的文字段for sentence in sentences:# 将字符串类型转换成字节类型后发送clientSocket.send(sentence.encode('utf-8'))time.sleep(0.1)clientSocket.send("EOF".encode())  # 最后自动发送EOF表示消息传输完毕time.sleep(0.1)return# 接收文件def file_recv(filename, clientSocket):file = open(filename, "w", encoding='utf-8')sentence = clientSocket.recv(1024).decode('utf-8')while sentence != "EOF":# 将接收的文字写入文件file.write(sentence)sentence = clientSocket.recv(1024).decode('utf-8')print("服务器收到文件!可在当前文件夹下查看")return# 发送信息def msg_send(content, clientSocket):# clientSocket.send(("当前为消息的传输").encode('utf-8'))  # 首先告知对方当前进行的是消息的传输time.sleep(0.1)  # 防止粘包sentences = []# 将content切割成长度为1024的一段段字符串 最后一段<=1024while len(content) > 0:sentences.append(content[:min(len(content), 1024)])content = content[min(len(content), 1024):]  # 割了就扔掉# 循环发送切割后的消息段for sentence in sentences:# 将字符串类型转换成字节类型后发送clientSocket.send(sentence.encode('utf-8'))time.sleep(0.1)clientSocket.send("EOF".encode())  # 最后自动发送EOF表示消息传输完毕time.sleep(0.1)# 接收消息# 接收消息def msg_recv(clientSocket):sentences = ""sentence = clientSocket.recv(1024).decode('utf-8')while sentence != "EOF":  # 消息传输未完毕sentences += sentence  # 拼接字符串sentence = clientSocket.recv(1024).decode('utf-8')  # 继续接收# print(sentences)  # 打印接收到的消息return sentences# 服务器收取来自客户端的消息或文件def recv_proc(connectionSocket):link = connectionSocket.recv(1024).decode('utf-8')link = link.split(":")  # 以 : 进行分隔成两个字符串from_link = link[0]to_link = link[1]global conn_pool  # 使用维护的连接 若想在函数内部对函数外的变量进行操作,就需要在函数内部声明其为global# 如果接收方不存在且不是服务器Serverif not conn_pool.get(to_link) and to_link != "Server":  # get()函数返回指定键的valueusers = ""for key, value in conn_pool.items():  # items() 函数作用:以列表返回可遍历的(键, 值) 元组数组。users += key+' 'connectionSocket.send("Message From Server".encode('utf-8'))time.sleep(0.1)connectionSocket.send(("NotExist%s" % users).endcode('utf-8'))return 2, "", "", ""sentences = ""parse = connectionSocket.recv(1024).decode('utf-8')print(parse)  # 测试测试测试# 判断是文件、退出标志还是信息if parse[:4] == "file":sentences = parsefile_recv(parse[5:], connectionSocket)elif parse == ":q":  # 退出连接sentences = parsereturn 1, sentences, from_link, to_linkelif parse == "msg":sentences = msg_recv(connectionSocket)return 0, sentences, from_link, to_link
# 服务端发def send_proc(parse, from_link, to_link):global conn_poolif parse == ":q":conn_pool[from_link].send(("Message From Server").encode('utf-8'))time.sleep(0.1)conn_pool[from_link].send(parse.encode('utf-8'))return 1connectionSocket = conn_pool[to_link]print("用户 %s 向用户 %s 发送消息" % (from_link, to_link))if to_link != "Server":  # 不是和服务器聊天,而是和其他用户connectionSocket.send(("Message From %s" % from_link).encode())connectionSocket.send(parse.encode('utf-8'))else:print("Receive from %s:" % name, end='')if parse[0:4] == "file":if to_link != "Server":file_send(parse[5:], connectionSocket)print("文件转发成功")else:if to_link != "Server":msg_send(parse, connectionSocket)else:print(parse)return 0# 服务器作为一个中转站,先接收,再发送def main_proc(connectionSocket, name):global conn_poolwhile 1:fg, parse, from_link, to_link = recv_proc(connectionSocket)if fg == 2:  # 如果接收方不存在且不是服务器Servercontinuefg = send_proc(parse, from_link, to_link)if fg == 1:  # 退出连接breakdel conn_pool[name]  # 连接关闭,删除映射关系print("用户 %s 已下线(断开连接)" % name)connectionSocket.close()serverPort = 2121
# 创建套接字
serverSocker = socket(AF_INET, SOCK_STREAM)
serverSocker.bind(('', serverPort))
serverSocker.listen(1)
global conn_pool  # 维护的连接
conn_pool = dict()  # 用户名:打开的tcp连接
conn_pool["Server"] = serverPort
print("我已经准备好提供服务啦")
# 创建线程池 最多为5个用户建立“群聊”
pool = ThreadPoolExecutor(max_workers=5)
while 1:connectionSocket, addr = serverSocker.accept()name = connectionSocket.recv(1024).decode('utf-8')  # 接收线程名保存在name中while conn_pool.get(name):connectionSocket.send("用户名已存在,请重新输入!".encode('utf-8'))name = connectionSocket.recv(1024).decode('utf-8')  # 重新接收connectionSocket.send("加入聊天成功!".encode('utf-8'))conn_pool[name] = connectionSocketprint("与来自 %s 的用户 %s 建立连接" % (str(addr), name))# connectionSocket,name是函数main_proc的参数pool.submit(main_proc, connectionSocket, name)
pool.shutdown(wait=True)  # wait=True表示关闭线程池之前需要等待所有工作线程结束
Client
from socket import *
from threading import Thread
import time# 发送信息def msg_send(content, clientSocket):clientSocket.send(("当前为消息的传输:").encode('utf-8'))  # 首先告知对方当前进行的是消息的传输time.sleep(0.1)  # 防止粘包sentences = []# 将content切割成长度为1024的一段段字符串 最后一段<=1024while len(content) > 0:sentences.append(content[:min(len(content), 1024)])content = content[min(len(content), 1024):]  # 割了就扔掉# 循环发送切割后的消息段for sentence in sentences:# 将字符串类型转换成字节类型后发送clientSocket.send(sentence.encode('utf-8'))time.sleep(0.1)clientSocket.send("EOF".encode())  # 最后自动发送EOF表示消息传输完毕time.sleep(0.1)# 接收消息def msg_recv(clientSocket):sentences = ""sentence = clientSocket.recv(1024).decode('utf-8')while sentence != "EOF":  # 消息传输未完毕sentences += sentence  # 拼接字符串sentence = clientSocket.recv(1024).decode('utf-8')  # 继续接收print(sentences, file=fw)  # 打印接收到的消息fw.flush()return# 发送文件def file_send(filename, clientSocket):# 异常处理 文件不存在则返回错误信息try:file = open(filename, encoding='utf-8')except FileNotFoundError:print("没找到文件,请检查你的输入")sentences = []content = file.read()# clientSocket.send(("即将传输文件:"+filename).encode('utf-8'))time.sleep(0.1)# 将content切割成长度为1024的一段段文字 最后一段<=1024while len(content) > 0:sentences.append(content[:min(len(content), 1024)])content = content[min(len(content), 1024):]  # 割了就扔掉# 循环发送切割后的文字段for sentence in sentences:# 将字符串类型转换成字节类型后发送clientSocket.send(sentence.encode('utf-8'))time.sleep(0.1)clientSocket.send("EOF".encode())  # 最后自动发送EOF表示消息传输完毕time.sleep(0.1)return# 接收文件def file_recv(filename, clientSocket):fil = open(filename, "w", encoding='utf-8')sentence = clientSocket.recv(1024).decode()while sentence != "EOF":# 将接收的文字写入文件fil.write(sentence)sentence = clientSocket.recv(1024).decode()# print("已成功接收文件!可在当前文件夹下查看", file=fil)  # 打印接收到的消息fil.flush()print("文件接收成功!可在当前文件夹下查看", file=fw)fw.flush()return# 发送线程
def send_proc(clientSocket, name):fg = True  # 信号while fg:to_name = input("请输入你想要聊天的对象:")clientSocket.send((name+":"+to_name).encode('utf-8'))  # 告知服务器收发双方名字time.sleep(0.5)  # 阻塞 等待收线程完成global existif exist:exist = False  # ????continueparse = input("请选择服务:\nfile:文件名\nmsg\n:q\n")clientSocket.send(parse.encode('utf-8'))if parse == "msg":content = input("请输入消息:")# msg_send(content,clientSocket)clientSocket.send(content.encode('utf-8'))clientSocket.send(("EOF").encode('utf-8'))elif parse[:4] == "file":file_send(parse[5:], clientSocket)elif parse == ":q":print(("您已下线"))clientSocket.close()
# 收线程def recv_proc(clientSocket):fg = Truewhile fg:from_whom = clientSocket.recv(1024).decode('utf-8')  # 来自谁parse = clientSocket.recv(1024).decode('utf-8')  # 内容是if parse[:4] == "file":print('\n%s(文件)' % from_whom, end=":", file=fw)fw.flush()file_recv(parse[5:], clientSocket)elif parse == ":q":fg = False  # 退出循环elif parse[:8] == "NotExist":print('%s' % from_whom, end=':')  # 输出Message From Serverprint("User Not Found")print("User list: %s" % parse[8:])global existexist = True  # 没找到接收方else:print('\n%s' % from_whom, end=':', file=fw)fw.flush()msg_recv(clientSocket)returnseverName = '127.0.0.1'
severPort = 2121
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect((severName, severPort))name = input("请输入你用于交流的用户名:")
clientSocket.send(name.encode('utf-8'))  # 发送给服务器校验(是否重复)并注册(加入字典)
reply = clientSocket.recv(1024).decode('utf-8')  # 接收服务器的校验结果
while reply == "用户名已存在":print(reply)name = input("请输入你用于交流的用户名:")clientSocket.send(name.encode('utf-8'))reply = clientSocket.recv(1024).decode('utf-8')
print(reply)
fw = open(name+'.output', "w", encoding='utf-8')  # 开一个文件当做用户的聊天框
fw.write("这里是%s的聊天框" % name)
fw.flush()  # 将缓冲区中的数据立刻写入文件global exist  # 用于确定接收方是否存在的信号量
exist = False
# 开启收、发的线程
send_task = Thread(target=send_proc, args=(clientSocket, name))
recv_task = Thread(target=recv_proc, args=(clientSocket,))
send_task.start()
recv_task.start()
send_task.join()  # 使用join函数,主线程将被阻塞,一直等待被使用了join方法的线程运行完成
recv_task.join()
1.测试重复用户名

在这里插入图片描述

2.测试发消息/文件

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/57203.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数字 IC 设计、FPGA 设计秋招笔试题目、答案、解析(4)2022 乐鑫数字芯片提前批笔试

单选题 1、以下关于 System Verilog 的描述&#xff0c;正确的是&#xff08; &#xff09; A. sv 中可以用 logic 代替 Verilog 中的 wire 和 reg 类型 B. sv 中&#xff0c; 定义成 reg 的信号会被综合成触发器 C. sv 中的 function 语言不可被综合 D. 其他都不正确 …

数字 IC 设计职位经典笔/面试题(二)

共100道经典笔试、面试题目&#xff08;文末可全领&#xff09; FPGA 中可以综合实现为 RAM/ROM/CAM 的三种资源及其注意事项&#xff1f; 三种资源&#xff1a;BLOCK RAM&#xff0c;触发器&#xff08;FF&#xff09;&#xff0c;查找表&#xff08;LUT&#xff09;&#xf…

数字IC设计工程师笔试面试经典100题-有答案

转自知乎答主ictown_数字IC设计工程师笔试面试经典100题-有答案-陈恩 1&#xff1a;什么是同步逻辑和异步逻辑&#xff1f;&#xff08;汉王&#xff09; 同步逻辑是时钟之间有固定的因果关系。异步逻辑是各时钟之间没有固定的因果关系。 同步时序逻辑电路的特点&#xff1a;各…

汇顶2018年 IC校招笔试题目

前言 后面,打算整理下数字ic笔试面试题目,希望以此为出发点,补充知识点!声明:个人觉得,学习期间,基本上都是知识的搬运,所以本博客所有内容都可以被大家引用!为了大家方便引用,博客内的图片都没有加博客的水印(除非不是自己的或者没看到)!这篇文章会基于下面这些文…

请收下这份数字IC面试超强攻略!(内附大厂面试题目)

2022年马上就要结束了&#xff0c;想必今年有很多同学也已经感受到IC行业的门槛在不断提升&#xff0c;这一点尤其在面试的过程中感受明显。 前两年的时候&#xff0c;面试官有可能问一些比较简单的问题就能通过&#xff0c;今年可就没那么简单了&#xff0c;必须提前做好相关…

数字IC笔试题3

目录 1.一个八位D/A转换器最小电压增量为0.01V&#xff0c;当输10011100时&#xff0c;输出电压为&#xff08;D&#xff09;V 2.下述概念中不属于面向对象这种编程范畴的是&#xff08;D&#xff09; 3.组合逻辑电路通常由&#xff08;B&#xff09;组合而成 4.三极管作为…

数字IC笔试题4

目录 1.[单选题]下列电路中属于时序逻辑电路的是&#xff08;B&#xff09; 2.[单选题]关于同步设计描述错误的是&#xff08;D&#xff09; 3.[多选题]下面哪种措施不能减少亚稳态影响&#xff08;CD&#xff09; 4.[单选题]状态机没有冗余状态时&#xff0c;可以不写defa…

海康威视 2024届 数字逻辑设计 实习笔试分析

说明 记录一下 5月11日晚&#xff0c;做的海康威视的一场笔试。分享给需要的IC人。 岗位&#xff1a;数字逻辑设计工程师&#xff08;浙江 杭州&#xff09; 转载需要本人同意&#xff01; 我的见解不一定都是准确的&#xff0c;欢迎评论区交流指正~~ 单选题 1、&#xff…

数字IC设计/FPGA工程师秋招面经

秋招面经 秋招总结迷茫期低谷期兴奋期秋招面试常问问题投递公司学习的FPGA课程总结 秋招总结 已经一个多月没更新博客了&#xff0c;并不是因为博主的只是储备量空了&#xff0c;而是因为我去准备秋招去了&#xff0c;接下来将会恢复博客的更新&#xff0c;速度不会太快&#…

数字IC设计工程师笔试面试经典100题

数字IC设计工程师笔试面试经典100题 https://blog.csdn.net/qq_41394155/article/details/89349935 ASIC–模拟版图工程师 https://blog.csdn.net/qq_41394155/article/details/89208062 ASIC–DFT可测性设计工程师 https://blog.csdn.net/qq_41394155/article/details/8836502…

数字IC笔试题1

目录 单选 1.关于亚稳态的描述错误的是&#xff08;A&#xff09; 2.一段程序如下&#xff0c;请问在45这个时刻上&#xff0c;A B的值各是多少&#xff08;B&#xff09; 3.下列关于综合的说法哪项是不正确的&#xff08;B&#xff09; 4.当功能覆盖率&#xff08;Functi…

数字IC笔试面试常考问题及答案汇总(内含各岗位大厂题目)

经历了无数的笔试面试之后&#xff0c;不知道大家有没有发现数字IC的笔试面试还是有很多共通之处和规律可循的。所以一定要掌握笔试面试常考的问题。 数字IC笔试面试常考问题及答案汇总&#xff08;文末可领全部哦~&#xff09; 验证方向&#xff08;部分题目&#xff09; Q1…

数字IC笔试/面试题

1、什么是同步逻辑和异步逻辑&#xff1f; 同步逻辑是时钟之间有固定的因果关系。异步逻辑是各时钟之间没有固定的因果关系。 同步时序逻辑的特点&#xff1a;各触发器的时钟端全部连接在一起&#xff0c;并接在系统的时钟端&#xff0c;只有当时钟脉冲到来时&#xff0c;电路…

数字IC笔试面试常考问题及答案

来源&#xff1a;知乎 链接&#xff1a;https://zhuanlan.zhihu.com/p/261298869 基础知识 原理务必理解透彻。 锁存器的结构-DFF的结构-建立保持时间-亚稳态-STA-CDC。 亚稳态的成因&#xff0c;危害&#xff0c;解决方法。 建立保持时间的计算&#xff0c;违例的Fix&#x…

3D建模除了日常工作,私下还可以赚外快哦,分分钟嗨赚

学习了游戏建模&#xff0c;肯定是想赚些外快的&#xff0c;可是有哪些地方可以提供这些方便呢&#xff1f;接下来陌陌就来说说了 APP和网站 八戒网&#xff1a;一个比较老的网站&#xff0c;会有一些企业发单&#xff0c;有很多任务&#xff0c;如果能力够不仅能赚取还能给对…

网上赚钱并不适合所有人!你为何没有在网上赚到钱!

为何100个人在网上开端挣钱&#xff0c;最后能挣钱的不到10个人呢&#xff1f;其实网上现在挣钱早已不是早期那么简略了&#xff01;互联网最开端也许是为了把各个地方的人链接在一起&#xff0c;可是不知道从什么时候开端互联网上的人逐渐形成了一个集体然后再到一个圈子。 ​…

飞迈阁带你了解网上赚钱

中国互联网的发展近20年左右&#xff0c;网兼也曾经有过非常多的值得很多人回忆与唠嗑的时​代&#xff0c;每个时代都存在着变富的人&#xff0c;在这些人的背后有的是沧桑&#xff0c;有的是肮脏&#xff0c;网兼就是如此&#xff0c;它本来就差不多是一个毁誉参半的圈子。 当…

AI绘画美女项目成功案例分享:3种变现方式让你赚翻!

的“真人AI绘画美女项目”是指使用人工智能技术绘制美女人脸的项目。这些图片通常呈现出高度的美感和完美的外貌&#xff0c;很难分辨其真实性。这类项目在抖音、小红书等社交平台上备受欢迎&#xff0c;吸引了大量的粉丝和点赞&#xff0c;尽管有人认识到这些图片是使用AI绘制…

美女画画赚钱月入10万,不懂画画你也可以月入1万

今天打开腾讯新闻&#xff0c;看到了这么一个信息&#xff0c; 这条新闻你可能也看到了&#xff0c;现在我把它贴出来&#xff0c;不妨再看一次&#xff01; 视频当中的主角&#xff1a;潘绫莹&#xff0c;从事的是油画定制&#xff0c;一副作品3800起&#xff0c;淡季的时候一…