• Stars
    star
    173
  • Rank 220,124 (Top 5 %)
  • Language
    Python
  • Created almost 8 years ago
  • Updated almost 8 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

计算机网络的期末Project,用Python编写的聊天室

功能

  • Diffie-Hellman 密钥交换安全传输(启动时第一件事)
  • 用AES加密所有的传输内容
  • 包分为OpCode和Parameters,用binary序列化反序列化Parameters
  • 使用数据库存储用户信息、好友关系、房间信息、加入房间状态、所有聊天记录
  • tkinter GUI
  • 有新消息时自动滚动到底部
  • 窗口放大缩小
  • 服务器、客户端通过JSON文件配置
  • 联系人列表;按照最后发消息的时间排序好友和群;未读的消息用红点标注数量;显示并实时更新在线状态
  • 加好友功能,对方收到通知,通过/拒绝/推迟到下次登入时询问
  • 防止重复打开窗口,如果已经打开则使窗口获得焦点
  • 账号只能在一处登入,在别处登入时把原来登入的踢下线
  • 再次打开时恢复所有聊天记录、用户离线时收到的未读的消息用红点标注数量
  • 支持多行内容(Enter换行,Ctrl+Enter发送);支持聊天字体的设置
  • 支持图片传输
  • 群聊功能、加群、创建群
  • 群聊中显示群成员(双击打开聊天窗口/发送好友请求);实时显示群成员在线状态,置顶在线的成员
  • 智能的联系人列表中的最近消息(同QQ,群聊则显示发送者昵称,图片则显示[图片消息],自动处理换行)

安装说明

Python版本: 3.5

pip install pycrypto # 用于AES加密
pip install Pillow # 支持JPG等格式图片的发送

也可以运行

pip install -r requirements.txt

运行方法

python run_client.py
python run_server.py

(一次只能运行一个server,但可以运行N个client)

配置文件

server和client共用config.json

{
  "crypto": {
    "base": ..,
    "modulus": ...
  },
  "client": {
    "server_ip": "127.0.0.1",
    "server_port": 8111
  },
  "server": {
    "bind_ip": "0.0.0.0",
    "bind_port": 8111
  }
}

大多都容易理解,需要注意的是crypto部分,这里的basemodulus是Diffie-Hellman密钥交换时用到的,应该为两个大素数。

文件目录

│  config.json
│  README.md
│  run_client.py
│  run_server.py
│
├─client
│  │  __init__.py
│  │
│  ├─components
│  │      contact_item.py
│  │      vertical_scrolled_frame.py
│  │      __init__.py
│  │
│  ├─forms
│  │      boilerplate.txt
│  │      chat_form.py
│  │      contacts_form.py
│  │      login_form.py
│  │      register_form.py
│  │      __init__.py
│  │
│  ├─memory
│  │      __init__.py
│  │
│  └─util
│      │  __init__.py
│      │
│      └─socket_listener
│              __init__.py
│
├─common
│  │  config.py
│  │  global_vars.py
│  │  __init__.py
│  │
│  ├─cryptography
│  │      crypt.py
│  │      prime.py
│  │      __init__.py
│  │
│  ├─message
│  │      __init__.py
│  │
│  ├─transmission
│  │      secure_channel.py
│  │      __init__.py
│  │
│  └─util
│          __init__.py
│
└─server
    │  database.db
    │  main.sql
    │  __init__.py
    │
    ├─broadcast
    │      __init__.py
    │
    ├─event_handler
    │      add_friend.py
    │      client_echo.py
    │      create_room.py
    │      join_room.py
    │      login.py
    │      query_room_users.py
    │      register.py
    │      resolve_friend_request.py
    │      send_message.py
    │      __init__.py
    │
    ├─memory
    │      __init__.py
    │
    └─util
        │  __init__.py
        │
        └─database
                __init__.py

预览图

1 2 3 4 5 6 7 8

自制聊天协议说明

本聊天协议受到HTTP协议启发

  1. 无状态(除了登入操作之外)。
  2. Request Body和Response Body使用键值对的方式,键为string,值可以为任意类型。

略作了修改

  1. 登入时设置socket状态,后续传输不必再次说明身份。
  2. 每个包头加入Request/Response Type,每个Type对应一种固定的操作,对应固定的参数列表。
  3. 使用二进制而非类JSON方式传输,节省流量。

这种设计的优点

  1. 简单易懂,易于测试(因为无状态)。
  2. 灵活方便,无需为不同的操作类型写不同的处理程序。
  3. 可以传输非常复杂的数据结构(如:登入时的所有N条未读消息(每条都含有发件人/时间/消息内容/甚至图片二进制)都是放在一个包里的)。

这种设计的缺点

  1. 每个字段要指定一个key(如:user,pwd),每个value的类型要有一个byte指定,略浪费流量。

增加安全性,防止被窃听:

  1. 自制的安全传输协议,在启动时会使用Diffie-Hellman算法与服务器交换密钥。
  2. 交换完密钥后,所有的传输都会经过AES加密。
  3. 客户端和服务器除了在协议上需要达到共识,不需要共享任何其他数据。
  4. 在不安全的信道上,就算所有数据都被窃听,窃听者也无法解密消息内容。

缺点:

  1. 无法防中间人攻击(没有做数字签名等)。

8

协议详细说明

注:具体实现可以看src/common/cryptographysrc/common/transmissionsrc/common/message

协议设计的宗旨是:无状态、分层设计、以先发送长度再发送内容的方式设计。

网络包分为四层,前三层格式一致,第四层是值层,格式根据值类型不同而不同。构造分别如下:

层1(解密前):

  1. Length of Message Body (4Bytes)
  2. Length of AES padding (1Byte) AES加密填充用
  3. AES IV (16Bytes) AES初始向量
  4. Message Body 被AES加密的内容

层2(解密后):

  1. Message Type (4Bytes) 定义MessageType,见src/common/message
  2. Array of parameters.. N个层3的数据

层3(参数):

  1. Type of Parameter (1Byte) 定义VAR_TYPE,见src/common/message
  2. Length of Body (4 Bytes)
  3. Body of Parameter 具体层4的数据,怎么解释需要根据VAR_TYPE决定,见层4

层4(基础类型如int、str、bool、float、binary等):

  1. Packed Data (Using struct.pack in Python) (直接转成bytes)

层4(List):

  1. Array of Level 3 Data Pack (N个层3的数据)

层4(Dictionary):

  1. Length of Key (1 Byte) Key的长度
  2. Key Key的值(字符串)
  3. Level 3 Data Pack 层3数据作为Value的值
  4. Repeat.. 重复123

一般来说,真正使用时,会选择直接发送一个List或者Dictionary作为层3,这样可以一次和服务器交换多个参数。

比如self.sc.send(MessageType.login, [username, password])

这种设计非常强大,结合src/common/transmission中的AES加密,可以无缝和服务器安全交换非常复杂的数据。比如,一个用户的所有离线未读消息(有N条,每条可能是不同的房间、不用的发送者,都包含不同的时间、字体大小,可能还有图片),可以通过一个包发送给客户端,效率非常高。

用SQLite存储用户信息和未读消息

数据库在src/server/database.db,结构如下:

CREATE TABLE "chat_history" (
"id"  INTEGER NOT NULL,
"user_id"  INTEGER,
"target_id"  INTEGER,
"target_type"  TEXT,
"data"  BLOB,
"sent"  INTEGER,
PRIMARY KEY ("id" ASC)
);

CREATE TABLE "friends" (
"from_user_id"  INTEGER NOT NULL,
"to_user_id"  INTEGER NOT NULL,
"accepted"  TEXT,
PRIMARY KEY ("from_user_id" ASC, "to_user_id")
);

CREATE TABLE "rooms" (
"id"  INTEGER NOT NULL,
"room_name"  TEXT,
PRIMARY KEY ("id")
);

CREATE TABLE "room_user" (
"id"  INTEGER NOT NULL,
"room_id"  INTEGER,
"user_id"  INTEGER,
PRIMARY KEY ("id")
);

CREATE TABLE "users" (
"id"  INTEGER NOT NULL,
"username"  TEXT,
"password"  TEXT,
"nickname"  TEXT,
PRIMARY KEY ("id" ASC)
);

比较有趣的是消息记录,这里直接用BLOB层2的消息存下来。

现在我做的是消息记录全保存,就直接在服务器处理消息之前,把消息写入数据库,如果用户在线,sent设置为True,否则为False

如果不希望保存所有消息,只希望保存未读消息,那么就去掉sent属性,只在用户不在线时写数据库,在用户在线后把数据读出来、发给用户然后删除即可。

两个有启发性的问题

大图传输失败?(数据包20KB以下不存在此问题)

data = socket.recv(length_of_message)

第一感觉:接收length_of_message个字节,收满才继续执行程序。

真正含义:缓存区大小为length_of_message,接收一次数据!(缓存区满会继续,但继续不代表收满)

TCP只保证数据到达先后顺序/不会漏也不会发重,但是不保证每次会到达多少数据!

解决方法:

一定要在最先4个Bytes告知消息长度,然后用:

while(bytes_received<bytes_total):
	data=socket.recv(bytes_total-bytes_received)
	bytes_received+=len(data)
	buffer+=data

对于select等非阻塞socket这个问题更加复杂一些,不过原理是相同的。

Windows和Linux之间互发消息,消息无法解读。

Python在不同系统下long的长度不一样。

Python内存中字节序也不一样。

解决方法:

在打包时统一转换为“network byte order”,即big endian,long统一为32位。(可表示4GB长度,够用)

解码时解成自己系统相对应的,放入内存中。

More Repositories

1

fdty

复旦体育理论考试 自动做题器
HTML
193
star
2

treebox

an interactive TreeMap visualization - Please star if you like this project
JavaScript
69
star
3

fuzzy-expert-system-buy-dslr-camera

人工智能课程Project —— 使用模糊专家系统做单反相机购买推荐
JavaScript
44
star
4

ztype-trainer

Trainer for the famous typing game ZType (http://zty.pe/), 6 effects
JavaScript
40
star
5

pj-crash-course-with-flask

为Python Flask零基础同学写的PJ速成课,包含教程和实战代码
HTML
32
star
6

seedbox-bot

Seedbox automation bot, featuring rss and auto deletion. Compatible with multiple WebUIs. Supports multiple user.
JavaScript
29
star
7

ListaryWithWinKey

Start Listary with Win key only, completely replacing the system search box.
C#
28
star
8

circle

专业在线协作,就和建微信群一样简单
PHP
7
star
9

rutorrent-auto-delete

Auto delete old torrents to keep disk space usage under a certain ratio and prevent rutorrent from crashing.
JavaScript
7
star
10

k

Enhanced `kubectl` based on `kubectl`; Supercharge your productivity - short aliases for multiple clusters, namespace override, shell scripting capabilities, useful tools such as "touch" & "watch K8S resources and show diff"
Go
6
star
11

breeze

an all-in-one browser extension, meant to make reading & note-taking easier
JavaScript
6
star
12

jigsaw-puzzle

七巧板游戏 图形人机交互 - 计算机图形学 Project 2
JavaScript
5
star
13

3launch

Launch your favorite programs with only 3 keystrokes !
C#
5
star
14

qlearning-hanoi

Play the hanoi game with reinforcement learning
Python
5
star
15

njq2

jq-like in node
JavaScript
3
star
16

md-edit

Native-app-like cross-platform Markdown Editor based on Electron, with live preview, code highlight, TeX math and PDF export support
JavaScript
3
star
17

img-with-aspect-ratio

An unconventional but great JavaScript solution for "image resize and keep aspect ratio".
JavaScript
3
star
18

snowflakes-audio-visualization

暗夜雪花 音频可视化 - 计算机图形学 Project 1
JavaScript
2
star
19

kubectl-watch-diff

Watch & pretty print diff, for kubectl
JavaScript
2
star
20

txt-to-sql-converter

NodeJS space-separated database text file to sql insert statements converter
JavaScript
2
star
21

js-shell

Automate your shell with JavaScript.
JavaScript
2
star
22

estate-agent-website

王轲的数据库期末Project-前端
JavaScript
2
star
23

html-find-replace-element-attrs

Find (or replace, sync/async) attributes of elements (e.g. img src) in an html string
JavaScript
2
star
24

estate-agent

王轲的数据库期末Project-后端
PHP
2
star
25

react-crontab-input

a crontab.guru/ replica as a react component, with i18n support
JavaScript
1
star
26

js-responsive-sokoban

Responsive sokoban game written in JS. Fully functional, 35kb gzipped
JavaScript
1
star
27

pt-rss-filter-proxy

A proxy to filter PT rss feeds according to file size / freeleech or not.
JavaScript
1
star
28

js-select-word-single-click

JS algorithm for selecting word with a single click
JavaScript
1
star
29

log-viewer

Hackable log viewer built with `nw.js` and `react`.
JavaScript
1
star
30

dirsync

An off-site data backup solution that is efficient, incremental and can prevent data degradation.
JavaScript
1
star
31

3d-shooter

3D射击游戏 真实感景物 - 计算机图形学 Project 3
JavaScript
1
star
32

chrome-force-proxy

JavaScript
1
star
33

writing-diff

Using ```git-diff``` to print the diff between original & revised version of a piece of writing to an html file.
JavaScript
1
star